From ad3e98c1eba439a265b3aa56dc5982439ae54266 Mon Sep 17 00:00:00 2001 From: Edison Su Date: Thu, 25 Oct 2012 10:26:49 -0700 Subject: [PATCH] @DB works on spring --- platform/storage/.project | 23 - platform/storage/pom.xml | 59 ++- .../storage/StorageOrchestratorImpl.java | 1 - .../cloudstack/storage/db/VolumeHostVO.java | 328 ------------- .../cloudstack/storage/volume/Volume.java | 17 + .../storage/volume/VolumeEvent.java | 34 ++ .../storage/volume/VolumeManagerImpl.java | 6 +- .../storage/volume/VolumeServiceImpl.java | 19 +- .../storage/volume/VolumeState.java | 71 +++ .../cloudstack/storage/volume/VolumeType.java | 27 ++ .../storage/volume/db/VolumeDao.java | 79 ++++ .../storage/volume/db/VolumeDaoImpl.java | 416 +++++++++++++++++ .../storage/volume/db/VolumeVO.java | 434 ++++++++++++++++++ .../cloudstack/storage/test/AopTest.java | 14 + .../storage/test/AopTestAdvice.java | 20 + .../storage/test/StorageFactoryBean.java | 42 ++ .../storage/test/storageContext.xml | 57 ++- .../storage/test/volumeServiceTest.java | 42 +- pom.xml | 2 +- setup/db/create-schema.sql | 1 + 20 files changed, 1311 insertions(+), 381 deletions(-) delete mode 100755 platform/storage/.project delete mode 100755 platform/storage/src/org/apache/cloudstack/storage/db/VolumeHostVO.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/volume/Volume.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/volume/VolumeEvent.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/volume/VolumeState.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/volume/VolumeType.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/volume/db/VolumeDao.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/volume/db/VolumeDaoImpl.java create mode 100644 platform/storage/src/org/apache/cloudstack/storage/volume/db/VolumeVO.java create mode 100644 platform/storage/test/org/apache/cloudstack/storage/test/AopTest.java create mode 100644 platform/storage/test/org/apache/cloudstack/storage/test/AopTestAdvice.java create mode 100644 platform/storage/test/org/apache/cloudstack/storage/test/StorageFactoryBean.java diff --git a/platform/storage/.project b/platform/storage/.project deleted file mode 100755 index ae8a72bd9ed..00000000000 --- a/platform/storage/.project +++ /dev/null @@ -1,23 +0,0 @@ - - - platform-storage - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.m2e.core.maven2Builder - - - - - - org.eclipse.m2e.core.maven2Nature - org.eclipse.jdt.core.javanature - - diff --git a/platform/storage/pom.xml b/platform/storage/pom.xml index f222a97b30b..614fccb08fd 100644 --- a/platform/storage/pom.xml +++ b/platform/storage/pom.xml @@ -1,21 +1,13 @@ - + 4.0.0 @@ -48,6 +40,37 @@ cloud-platform-api ${project.version} + + org.apache.openjpa + openjpa + 2.2.0 + + + mysql + mysql-connector-java + ${cs.mysql.version} + provided + + + org.mockito + mockito-all + 1.9.5 + + + org.aspectj + aspectjrt + 1.7.1 + + + org.aspectj + aspectjweaver + 1.7.1 + + + javax.inject + javax.inject + 1 + install diff --git a/platform/storage/src/org/apache/cloudstack/storage/StorageOrchestratorImpl.java b/platform/storage/src/org/apache/cloudstack/storage/StorageOrchestratorImpl.java index 00e6eaee036..7c88cae04da 100644 --- a/platform/storage/src/org/apache/cloudstack/storage/StorageOrchestratorImpl.java +++ b/platform/storage/src/org/apache/cloudstack/storage/StorageOrchestratorImpl.java @@ -27,7 +27,6 @@ import org.apache.cloudstack.platform.subsystem.api.storage.StorageProvider; import org.apache.cloudstack.platform.subsystem.api.storage.TemplateProfile; import org.apache.cloudstack.platform.subsystem.api.storage.VolumeProfile; import org.apache.cloudstack.platform.subsystem.api.storage.VolumeStrategy; -import org.apache.cloudstack.storage.db.VolumeHostVO; import org.apache.cloudstack.storage.image.ImageManager; import org.apache.cloudstack.storage.manager.BackupStorageManager; import org.apache.cloudstack.storage.manager.SecondaryStorageManager; diff --git a/platform/storage/src/org/apache/cloudstack/storage/db/VolumeHostVO.java b/platform/storage/src/org/apache/cloudstack/storage/db/VolumeHostVO.java deleted file mode 100755 index bb418640c97..00000000000 --- a/platform/storage/src/org/apache/cloudstack/storage/db/VolumeHostVO.java +++ /dev/null @@ -1,328 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package org.apache.cloudstack.storage.db; - -import java.util.Date; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; - -import org.apache.cloudstack.platform.subsystem.api.storage.DataObjectBackupStorageOperationState; -import org.apache.cloudstack.storage.VolumeBackupRef; - -//import com.cloud.storage.VMVolumeStorageResourceAssoc.Status; -import com.cloud.storage.Storage; -import com.cloud.storage.VMTemplateStorageResourceAssoc; -import com.cloud.storage.Storage.ImageFormat; -import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; -import com.cloud.utils.db.GenericDaoBase; - -/** - * Join table for storage hosts and volumes - * - */ -@Entity -@Table(name="volume_host_ref") -public class VolumeHostVO implements VolumeBackupRef { - @Id - @GeneratedValue(strategy=GenerationType.IDENTITY) - Long id; - - @Column(name="host_id") - private long hostId; - - @Column(name="volume_id") - private long volumeId; - - @Column(name="zone_id") - private long zoneId; - - @Column(name=GenericDaoBase.CREATED_COLUMN) - private Date created = null; - - @Column(name="last_updated") - @Temporal(value=TemporalType.TIMESTAMP) - private Date lastUpdated = null; - - @Column (name="download_pct") - private int downloadPercent; - - @Column (name="size") - private long size; - - @Column (name="physical_size") - private long physicalSize; - - @Column (name="download_state") - @Enumerated(EnumType.STRING) - private Status downloadState; - - @Column (name="opt_state") - @Enumerated(EnumType.STRING) - private DataObjectBackupStorageOperationState optState; - - @Column(name="checksum") - private String checksum; - - @Column (name="local_path") - private String localDownloadPath; - - @Column (name="error_str") - private String errorString; - - @Column (name="job_id") - private String jobId; - - @Column (name="install_path") - private String installPath; - - @Column (name="url") - private String downloadUrl; - - @Column(name="format") - private Storage.ImageFormat format; - - @Column(name="destroyed") - boolean destroyed = false; - - - public String getInstallPath() { - return installPath; - } - - public long getHostId() { - return hostId; - } - - public void setHostId(long hostId) { - this.hostId = hostId; - } - - - public long getVolumeId() { - return volumeId; - } - - - public void setVolumeId(long volumeId) { - this.volumeId = volumeId; - } - - - public long getZoneId() { - return zoneId; - } - - public void setZoneId(long zoneId) { - this.zoneId = zoneId; - } - - public int getDownloadPercent() { - return downloadPercent; - } - - - public void setDownloadPercent(int downloadPercent) { - this.downloadPercent = downloadPercent; - } - - - public void setDownloadState(Status downloadState) { - this.downloadState = downloadState; - } - - - - public long getId() { - return id; - } - - - - public Date getCreated() { - return created; - } - - public Date getLastUpdated() { - return lastUpdated; - } - - - public void setLastUpdated(Date date) { - lastUpdated = date; - } - - - public void setInstallPath(String installPath) { - this.installPath = installPath; - } - - - public Status getDownloadState() { - return downloadState; - } - - public String getChecksum() { - return checksum; - } - - public void setChecksum(String checksum) { - this.checksum = checksum; - } - - public VolumeHostVO(long hostId, long volumeId) { - super(); - this.hostId = hostId; - this.volumeId = volumeId; - } - - public VolumeHostVO(long hostId, long volumeId, long zoneId, Date lastUpdated, - int downloadPercent, Status downloadState, - String localDownloadPath, String errorString, String jobId, - String installPath, String downloadUrl, String checksum, ImageFormat format) { - //super(); - this.hostId = hostId; - this.volumeId = volumeId; - this.zoneId = zoneId; - this.lastUpdated = lastUpdated; - this.downloadPercent = downloadPercent; - this.downloadState = downloadState; - this.localDownloadPath = localDownloadPath; - this.errorString = errorString; - this.jobId = jobId; - this.installPath = installPath; - this.setDownloadUrl(downloadUrl); - this.checksum = checksum; - this.format = format; - } - - protected VolumeHostVO() { - - } - - - public void setLocalDownloadPath(String localPath) { - this.localDownloadPath = localPath; - } - - public String getLocalDownloadPath() { - return localDownloadPath; - } - - - public void setErrorString(String errorString) { - this.errorString = errorString; - } - - - public String getErrorString() { - return errorString; - } - - - public void setJobId(String jobId) { - this.jobId = jobId; - } - - - public String getJobId() { - return jobId; - } - - - public boolean equals(Object obj) { - if (obj instanceof VolumeHostVO) { - VolumeBackupRef other = (VolumeBackupRef)obj; - return (this.volumeId==other.getVolumeId() && this.hostId==other.getHostId()); - } - return false; - } - - - public int hashCode() { - Long tid = new Long(volumeId); - Long hid = new Long(hostId); - return tid.hashCode()+hid.hashCode(); - } - - public void setSize(long size) { - this.size = size; - } - - - public long getSize() { - return size; - } - - - public void setPhysicalSize(long physicalSize) { - this.physicalSize = physicalSize; - } - - - public long getPhysicalSize() { - return physicalSize; - } - - public void setDestroyed(boolean destroyed) { - this.destroyed = destroyed; - } - - - public boolean getDestroyed() { - return destroyed; - } - - public void setDownloadUrl(String downloadUrl) { - this.downloadUrl = downloadUrl; - } - - - public String getDownloadUrl() { - return downloadUrl; - } - - public Storage.ImageFormat getFormat() { - return format; - } - - public void setFormat(Storage.ImageFormat format) { - this.format = format; - } - - public String toString() { - return new StringBuilder("VolumeHost[").append(id).append("-").append(volumeId).append("-").append(hostId).append(installPath).append("]").toString(); - } - - public DataObjectBackupStorageOperationState getOperationState() { - return optState; - } - - public long getVolumeSize() { - // TODO Auto-generated method stub - return 0; - } - -} diff --git a/platform/storage/src/org/apache/cloudstack/storage/volume/Volume.java b/platform/storage/src/org/apache/cloudstack/storage/volume/Volume.java new file mode 100644 index 00000000000..15ab86b6067 --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/volume/Volume.java @@ -0,0 +1,17 @@ +package org.apache.cloudstack.storage.volume; + +import org.apache.cloudstack.storage.volume.db.VolumeVO; + +import com.cloud.utils.fsm.StateObject; + +public class Volume implements StateObject{ + private VolumeVO volumeVO; + @Override + public VolumeState getState() { + // TODO Auto-generated method stub + return null; + } + + + +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeEvent.java b/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeEvent.java new file mode 100644 index 00000000000..33d1261ead9 --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeEvent.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.storage.volume; + +public enum VolumeEvent { + CreateRequested, + CopyRequested, + CopySucceeded, + CopyFailed, + OperationFailed, + OperationSucceeded, + OperationRetry, + UploadRequested, + MigrationRequested, + SnapshotRequested, + DestroyRequested, + ExpungingRequested; +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeManagerImpl.java b/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeManagerImpl.java index 6d9bde85814..19e61a8fb33 100644 --- a/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeManagerImpl.java +++ b/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeManagerImpl.java @@ -40,13 +40,13 @@ public class VolumeManagerImpl implements VolumeManager { newVol.setInstanceId(oldVol.getInstanceId()); newVol.setRecreatable(oldVol.isRecreatable()); newVol.setReservationId(oldVol.getReservationId()); - - return _volumeDao.persist(newVol); + return null; + //return _volumeDao.persist(newVol); } public VolumeVO processEvent(Volume vol, Volume.Event event) throws NoTransitionException { - _volStateMachine.transitTo(vol, event, null, _volumeDao); + //_volStateMachine.transitTo(vol, event, null, _volumeDao); return _volumeDao.findById(vol.getId()); } diff --git a/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java b/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java index 4bf6f997739..57e5a684d37 100644 --- a/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java +++ b/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java @@ -18,24 +18,34 @@ */ package org.apache.cloudstack.storage.volume; +import org.apache.cloudstack.storage.volume.db.VolumeDao; +import org.apache.cloudstack.storage.volume.db.VolumeVO; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import com.cloud.api.commands.CreateVolumeCmd; +import com.cloud.storage.SnapshotVO; import com.cloud.storage.Volume; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.upgrade.dao.VersionDao; +import com.cloud.upgrade.dao.VersionVO; +import com.cloud.utils.db.DB; @Component public class VolumeServiceImpl implements VolumeService { - + @Autowired + VolumeDao _volumeDao; @Override public Volume createVolume(long volumeId) { // TODO Auto-generated method stub return null; } + @DB @Override public boolean deleteVolume(long volumeId) { - // TODO Auto-generated method stub - return false; + VolumeVO vol = new VolumeVO(VolumeType.ROOT, "root", 1, 1,1 ,1,1); + _volumeDao.persist(vol); + return true; } @Override @@ -61,5 +71,4 @@ public class VolumeServiceImpl implements VolumeService { // TODO Auto-generated method stub return false; } - } diff --git a/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeState.java b/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeState.java new file mode 100644 index 00000000000..6b81f007ea6 --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeState.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.storage.volume; + +import com.cloud.utils.fsm.StateMachine2; + +public enum VolumeState { + Allocated("The volume is allocated but has not been created yet."), + Creating("The volume is being created. getPoolId() should reflect the pool where it is being created."), + Ready("The volume is ready to be used."), + Migrating("The volume is migrating to other storage pool"), + Snapshotting("There is a snapshot created on this volume, not backed up to secondary storage yet"), + Expunging("The volume is being expunging"), + Destroy("The volume is destroyed, and can't be recovered."), + UploadOp ("The volume upload operation is in progress or in short the volume is on secondary storage"); + + String _description; + + private VolumeState(String description) { + _description = description; + } + + public static StateMachine2 getStateMachine() { + return s_fsm; + } + + public String getDescription() { + return _description; + } + + private final static StateMachine2 s_fsm = new StateMachine2(); + static { + s_fsm.addTransition(Allocated, VolumeEvent.CreateRequested, Creating); + s_fsm.addTransition(Allocated, VolumeEvent.DestroyRequested, Destroy); + s_fsm.addTransition(Creating, VolumeEvent.OperationRetry, Creating); + s_fsm.addTransition(Creating, VolumeEvent.OperationFailed, Allocated); + s_fsm.addTransition(Creating, VolumeEvent.OperationSucceeded, Ready); + s_fsm.addTransition(Creating, VolumeEvent.DestroyRequested, Destroy); + s_fsm.addTransition(Creating, VolumeEvent.CreateRequested, Creating); + s_fsm.addTransition(Allocated, VolumeEvent.UploadRequested, UploadOp); + s_fsm.addTransition(UploadOp, VolumeEvent.CopyRequested, Creating);// CopyRequested for volume from sec to primary storage + s_fsm.addTransition(Creating, VolumeEvent.CopySucceeded, Ready); + s_fsm.addTransition(Creating, VolumeEvent.CopyFailed, UploadOp);// Copying volume from sec to primary failed. + s_fsm.addTransition(UploadOp, VolumeEvent.DestroyRequested, Destroy); + s_fsm.addTransition(Ready, VolumeEvent.DestroyRequested, Destroy); + s_fsm.addTransition(Destroy, VolumeEvent.ExpungingRequested, Expunging); + s_fsm.addTransition(Ready, VolumeEvent.SnapshotRequested, Snapshotting); + s_fsm.addTransition(Snapshotting, VolumeEvent.OperationSucceeded, Ready); + s_fsm.addTransition(Snapshotting, VolumeEvent.OperationFailed, Ready); + s_fsm.addTransition(Ready, VolumeEvent.MigrationRequested, Migrating); + s_fsm.addTransition(Migrating, VolumeEvent.OperationSucceeded, Ready); + s_fsm.addTransition(Migrating, VolumeEvent.OperationFailed, Ready); + s_fsm.addTransition(Destroy, VolumeEvent.OperationSucceeded, Destroy); + } +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeType.java b/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeType.java new file mode 100644 index 00000000000..ca9bfed1123 --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/volume/VolumeType.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.storage.volume; + +public enum VolumeType { + UNKNOWN, + ROOT, + SWAP, + DATADISK, + ISO +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/volume/db/VolumeDao.java b/platform/storage/src/org/apache/cloudstack/storage/volume/db/VolumeDao.java new file mode 100644 index 00000000000..0ac26f90fd4 --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/volume/db/VolumeDao.java @@ -0,0 +1,79 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.storage.volume.db; + +import java.util.List; + +import org.apache.cloudstack.storage.volume.Volume; +import org.apache.cloudstack.storage.volume.VolumeEvent; +import org.apache.cloudstack.storage.volume.VolumeState; +import org.apache.cloudstack.storage.volume.VolumeType; + +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.storage.Storage.ImageFormat; +import com.cloud.utils.Pair; +import com.cloud.utils.db.GenericDao; +import com.cloud.utils.fsm.StateDao; + +public interface VolumeDao extends GenericDao, StateDao { + + List findDetachedByAccount(long accountId); + + List findByAccount(long accountId); + + Pair getCountAndTotalByPool(long poolId); + + Pair getNonDestroyedCountAndTotalByPool(long poolId); + + List findByInstance(long id); + + List findByInstanceAndType(long id, VolumeType vType); + + List findByInstanceIdDestroyed(long vmId); + + List findByAccountAndPod(long accountId, long podId); + + List findByTemplateAndZone(long templateId, long zoneId); + + void deleteVolumesByInstance(long instanceId); + + void attachVolume(long volumeId, long vmId, long deviceId); + + void detachVolume(long volumeId); + + boolean isAnyVolumeActivelyUsingTemplateOnPool(long templateId, long poolId); + + List findCreatedByInstance(long id); + + List findByPoolId(long poolId); + + List findByInstanceAndDeviceId(long instanceId, long deviceId); + + List findUsableVolumesForInstance(long instanceId); + + Long countAllocatedVolumesForAccount(long accountId); + + HypervisorType getHypervisorType(long volumeId); + + List listVolumesToBeDestroyed(); + + ImageFormat getImageFormat(Long volumeId); + + List findReadyRootVolumesByInstance(long instanceId); + + List listPoolIdsByVolumeCount(long dcId, Long podId, Long clusterId, long accountId); +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/volume/db/VolumeDaoImpl.java b/platform/storage/src/org/apache/cloudstack/storage/volume/db/VolumeDaoImpl.java new file mode 100644 index 00000000000..6557e8ac802 --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/volume/db/VolumeDaoImpl.java @@ -0,0 +1,416 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.storage.volume.db; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import javax.ejb.Local; + +import org.apache.cloudstack.storage.volume.VolumeEvent; +import org.apache.cloudstack.storage.volume.VolumeState; +import org.apache.cloudstack.storage.volume.VolumeType; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.server.ResourceTag.TaggedResourceType; +import com.cloud.storage.Storage.ImageFormat; +import com.cloud.tags.dao.ResourceTagsDaoImpl; +import com.cloud.utils.Pair; +import com.cloud.utils.component.ComponentLocator; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.GenericSearchBuilder; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Func; +import com.cloud.utils.db.SearchCriteria.Op; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.UpdateBuilder; +import com.cloud.utils.exception.CloudRuntimeException; + +@Local(value=VolumeDao.class) +@Component +public class VolumeDaoImpl extends GenericDaoBase implements VolumeDao { + private static final Logger s_logger = Logger.getLogger(VolumeDaoImpl.class); + protected final SearchBuilder DetachedAccountIdSearch; + protected final SearchBuilder TemplateZoneSearch; + protected final GenericSearchBuilder TotalSizeByPoolSearch; + protected final GenericSearchBuilder ActiveTemplateSearch; + protected final SearchBuilder InstanceStatesSearch; + protected final SearchBuilder AllFieldsSearch; + protected GenericSearchBuilder CountByAccount; + ResourceTagsDaoImpl _tagsDao = ComponentLocator.inject(ResourceTagsDaoImpl.class); + + protected static final String SELECT_VM_SQL = "SELECT DISTINCT instance_id from volumes v where v.host_id = ? and v.mirror_state = ?"; + protected static final String SELECT_HYPERTYPE_FROM_VOLUME = "SELECT c.hypervisor_type from volumes v, storage_pool s, cluster c where v.pool_id = s.id and s.cluster_id = c.id and v.id = ?"; + + private static final String ORDER_POOLS_NUMBER_OF_VOLUMES_FOR_ACCOUNT = "SELECT pool.id, SUM(IF(vol.state='Ready' AND vol.account_id = ?, 1, 0)) FROM `cloud`.`storage_pool` pool LEFT JOIN `cloud`.`volumes` vol ON pool.id = vol.pool_id WHERE pool.data_center_id = ? " + + " AND pool.pod_id = ? AND pool.cluster_id = ? " + + " GROUP BY pool.id ORDER BY 2 ASC "; + + @Override + public List findDetachedByAccount(long accountId) { + SearchCriteria sc = DetachedAccountIdSearch.create(); + sc.setParameters("accountId", accountId); + sc.setParameters("destroyed", VolumeState.Destroy); + return listBy(sc); + } + + @Override + public List findByAccount(long accountId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("accountId", accountId); + sc.setParameters("state", VolumeState.Ready); + return listBy(sc); + } + + @Override + public List findByInstance(long id) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("instanceId", id); + return listBy(sc); + } + + @Override + public List findByInstanceAndDeviceId(long instanceId, long deviceId){ + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("instanceId", instanceId); + sc.setParameters("deviceId", deviceId); + return listBy(sc); + } + + @Override + public List findByPoolId(long poolId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("poolId", poolId); + sc.setParameters("notDestroyed", VolumeState.Destroy); + sc.setParameters("vType", VolumeType.ROOT.toString()); + return listBy(sc); + } + + @Override + public List findCreatedByInstance(long id) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("instanceId", id); + sc.setParameters("state", VolumeState.Ready); + return listBy(sc); + } + + @Override + public List findUsableVolumesForInstance(long instanceId) { + SearchCriteria sc = InstanceStatesSearch.create(); + sc.setParameters("instance", instanceId); + sc.setParameters("states", VolumeState.Creating, VolumeState.Ready, VolumeState.Allocated); + + return listBy(sc); + } + + @Override + public List findByInstanceAndType(long id, VolumeType vType) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("instanceId", id); + sc.setParameters("vType", vType.toString()); + return listBy(sc); + } + + @Override + public List findByInstanceIdDestroyed(long vmId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("instanceId", vmId); + sc.setParameters("destroyed", VolumeState.Destroy); + return listBy(sc); + } + + @Override + public List findReadyRootVolumesByInstance(long instanceId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("instanceId", instanceId); + sc.setParameters("state", VolumeState.Ready); + sc.setParameters("vType", VolumeType.ROOT); + return listBy(sc); + } + + @Override + public List findByAccountAndPod(long accountId, long podId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("accountId", accountId); + sc.setParameters("pod", podId); + sc.setParameters("state", VolumeState.Ready); + + return listIncludingRemovedBy(sc); + } + + @Override + public List findByTemplateAndZone(long templateId, long zoneId) { + SearchCriteria sc = TemplateZoneSearch.create(); + sc.setParameters("template", templateId); + sc.setParameters("zone", zoneId); + + return listIncludingRemovedBy(sc); + } + + @Override + public boolean isAnyVolumeActivelyUsingTemplateOnPool(long templateId, long poolId) { + SearchCriteria sc = ActiveTemplateSearch.create(); + sc.setParameters("template", templateId); + sc.setParameters("pool", poolId); + + List results = customSearchIncludingRemoved(sc, null); + assert results.size() > 0 : "How can this return a size of " + results.size(); + + return results.get(0) > 0; + } + + @Override + public void deleteVolumesByInstance(long instanceId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("instanceId", instanceId); + expunge(sc); + } + + @Override + public void attachVolume(long volumeId, long vmId, long deviceId) { + VolumeVO volume = createForUpdate(volumeId); + volume.setInstanceId(vmId); + volume.setDeviceId(deviceId); + volume.setUpdated(new Date()); + volume.setAttached(new Date()); + update(volumeId, volume); + } + + @Override + public void detachVolume(long volumeId) { + VolumeVO volume = createForUpdate(volumeId); + volume.setInstanceId(null); + volume.setDeviceId(null); + volume.setUpdated(new Date()); + volume.setAttached(null); + update(volumeId, volume); + } + + @Override + @DB + public HypervisorType getHypervisorType(long volumeId) { + /*lookup from cluster of pool*/ + Transaction txn = Transaction.currentTxn(); + PreparedStatement pstmt = null; + + try { + String sql = SELECT_HYPERTYPE_FROM_VOLUME; + pstmt = txn.prepareAutoCloseStatement(sql); + pstmt.setLong(1, volumeId); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) { + return HypervisorType.getType(rs.getString(1)); + } + return HypervisorType.None; + } catch (SQLException e) { + throw new CloudRuntimeException("DB Exception on: " + SELECT_HYPERTYPE_FROM_VOLUME, e); + } catch (Throwable e) { + throw new CloudRuntimeException("Caught: " + SELECT_HYPERTYPE_FROM_VOLUME, e); + } + } + + @Override + public ImageFormat getImageFormat(Long volumeId) { + HypervisorType type = getHypervisorType(volumeId); + if ( type.equals(HypervisorType.KVM)) { + return ImageFormat.QCOW2; + } else if ( type.equals(HypervisorType.XenServer)) { + return ImageFormat.VHD; + } else if ( type.equals(HypervisorType.VMware)) { + return ImageFormat.OVA; + } else { + s_logger.warn("Do not support hypervisor " + type.toString()); + return null; + } + } + + protected VolumeDaoImpl() { + AllFieldsSearch = createSearchBuilder(); + AllFieldsSearch.and("state", AllFieldsSearch.entity().getState(), Op.EQ); + AllFieldsSearch.and("accountId", AllFieldsSearch.entity().getAccountId(), Op.EQ); + AllFieldsSearch.and("pod", AllFieldsSearch.entity().getPodId(), Op.EQ); + AllFieldsSearch.and("instanceId", AllFieldsSearch.entity().getInstanceId(), Op.EQ); + AllFieldsSearch.and("deviceId", AllFieldsSearch.entity().getDeviceId(), Op.EQ); + AllFieldsSearch.and("poolId", AllFieldsSearch.entity().getPoolId(), Op.EQ); + AllFieldsSearch.and("vType", AllFieldsSearch.entity().getVolumeType(), Op.EQ); + AllFieldsSearch.and("id", AllFieldsSearch.entity().getId(), Op.EQ); + AllFieldsSearch.and("destroyed", AllFieldsSearch.entity().getState(), Op.EQ); + AllFieldsSearch.and("notDestroyed", AllFieldsSearch.entity().getState(), Op.NEQ); + AllFieldsSearch.and("updatedCount", AllFieldsSearch.entity().getUpdatedCount(), Op.EQ); + AllFieldsSearch.done(); + + DetachedAccountIdSearch = createSearchBuilder(); + DetachedAccountIdSearch.and("accountId", DetachedAccountIdSearch.entity().getAccountId(), Op.EQ); + DetachedAccountIdSearch.and("destroyed", DetachedAccountIdSearch.entity().getState(), Op.NEQ); + DetachedAccountIdSearch.and("instanceId", DetachedAccountIdSearch.entity().getInstanceId(), Op.NULL); + DetachedAccountIdSearch.done(); + + TemplateZoneSearch = createSearchBuilder(); + TemplateZoneSearch.and("template", TemplateZoneSearch.entity().getTemplateId(), Op.EQ); + TemplateZoneSearch.and("zone", TemplateZoneSearch.entity().getDataCenterId(), Op.EQ); + TemplateZoneSearch.done(); + + TotalSizeByPoolSearch = createSearchBuilder(SumCount.class); + TotalSizeByPoolSearch.select("sum", Func.SUM, TotalSizeByPoolSearch.entity().getSize()); + TotalSizeByPoolSearch.select("count", Func.COUNT, (Object[])null); + TotalSizeByPoolSearch.and("poolId", TotalSizeByPoolSearch.entity().getPoolId(), Op.EQ); + TotalSizeByPoolSearch.and("removed", TotalSizeByPoolSearch.entity().getRemoved(), Op.NULL); + TotalSizeByPoolSearch.and("state", TotalSizeByPoolSearch.entity().getState(), Op.NEQ); + TotalSizeByPoolSearch.done(); + + ActiveTemplateSearch = createSearchBuilder(Long.class); + ActiveTemplateSearch.and("pool", ActiveTemplateSearch.entity().getPoolId(), Op.EQ); + ActiveTemplateSearch.and("template", ActiveTemplateSearch.entity().getTemplateId(), Op.EQ); + ActiveTemplateSearch.and("removed", ActiveTemplateSearch.entity().getRemoved(), Op.NULL); + ActiveTemplateSearch.select(null, Func.COUNT, null); + ActiveTemplateSearch.done(); + + InstanceStatesSearch = createSearchBuilder(); + InstanceStatesSearch.and("instance", InstanceStatesSearch.entity().getInstanceId(), Op.EQ); + InstanceStatesSearch.and("states", InstanceStatesSearch.entity().getState(), Op.IN); + InstanceStatesSearch.done(); + + CountByAccount = createSearchBuilder(Long.class); + CountByAccount.select(null, Func.COUNT, null); + CountByAccount.and("account", CountByAccount.entity().getAccountId(), SearchCriteria.Op.EQ); + CountByAccount.and("state", CountByAccount.entity().getState(), SearchCriteria.Op.NIN); + CountByAccount.done(); + } + + @Override @DB(txn=false) + public Pair getCountAndTotalByPool(long poolId) { + SearchCriteria sc = TotalSizeByPoolSearch.create(); + sc.setParameters("poolId", poolId); + List results = customSearch(sc, null); + SumCount sumCount = results.get(0); + return new Pair(sumCount.count, sumCount.sum); + } + + @Override + public Long countAllocatedVolumesForAccount(long accountId) { + SearchCriteria sc = CountByAccount.create(); + sc.setParameters("account", accountId); + sc.setParameters("state", VolumeState.Destroy); + return customSearch(sc, null).get(0); + } + + public static class SumCount { + public long sum; + public long count; + public SumCount() { + } + } + + @Override + public List listVolumesToBeDestroyed() { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("state", VolumeState.Destroy); + + return listBy(sc); + } + + @Override + public boolean updateState(VolumeState currentState, + VolumeEvent event, VolumeState nextState, VolumeVO vo, + Object data) { + + Long oldUpdated = vo.getUpdatedCount(); + Date oldUpdatedTime = vo.getUpdated(); + + SearchCriteria sc = AllFieldsSearch.create(); + 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((VolumeVO)vo, sc); + if (rows == 0 && s_logger.isDebugEnabled()) { + VolumeVO 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 volume: id=" + vo.getId() + ", as there is no such volume exists in the database anymore"); + } + } + return rows > 0; + } + + @Override + public List listPoolIdsByVolumeCount(long dcId, Long podId, Long clusterId, long accountId) { + Transaction txn = Transaction.currentTxn(); + PreparedStatement pstmt = null; + List result = new ArrayList(); + try { + String sql = ORDER_POOLS_NUMBER_OF_VOLUMES_FOR_ACCOUNT; + pstmt = txn.prepareAutoCloseStatement(sql); + pstmt.setLong(1, accountId); + pstmt.setLong(2, dcId); + pstmt.setLong(3, podId); + pstmt.setLong(4, clusterId); + + ResultSet rs = pstmt.executeQuery(); + while (rs.next()) { + result.add(rs.getLong(1)); + } + return result; + } catch (SQLException e) { + throw new CloudRuntimeException("DB Exception on: " + ORDER_POOLS_NUMBER_OF_VOLUMES_FOR_ACCOUNT, e); + } catch (Throwable e) { + throw new CloudRuntimeException("Caught: " + ORDER_POOLS_NUMBER_OF_VOLUMES_FOR_ACCOUNT, e); + } + } + + @Override @DB(txn=false) + public Pair getNonDestroyedCountAndTotalByPool(long poolId) { + SearchCriteria sc = TotalSizeByPoolSearch.create(); + sc.setParameters("poolId", poolId); + sc.setParameters("state", VolumeState.Destroy); + List results = customSearch(sc, null); + SumCount sumCount = results.get(0); + return new Pair(sumCount.count, sumCount.sum); + } + + @Override + @DB + public boolean remove(Long id) { + Transaction txn = Transaction.currentTxn(); + txn.start(); + VolumeVO entry = findById(id); + if (entry != null) { + _tagsDao.removeByIdAndType(id, TaggedResourceType.Volume); + } + boolean result = super.remove(id); + txn.commit(); + return result; + } +} diff --git a/platform/storage/src/org/apache/cloudstack/storage/volume/db/VolumeVO.java b/platform/storage/src/org/apache/cloudstack/storage/volume/db/VolumeVO.java new file mode 100644 index 00000000000..7dca42ec33b --- /dev/null +++ b/platform/storage/src/org/apache/cloudstack/storage/volume/db/VolumeVO.java @@ -0,0 +1,434 @@ +//Licensed to the Apache Software Foundation (ASF) under one +//or more contributor license agreements. See the NOTICE file +//distributed with this work for additional information +//regarding copyright ownership. The ASF licenses this file +//to you under the Apache License, Version 2.0 (the +//"License"); you may not use this file except in compliance +//with the License. You may obtain a copy of the License at +// +//http://www.apache.org/licenses/LICENSE-2.0 +// +//Unless required by applicable law or agreed to in writing, +//software distributed under the License is distributed on an +//"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +//KIND, either express or implied. See the License for the +//specific language governing permissions and limitations +//under the License. + +package org.apache.cloudstack.storage.volume.db; +import java.util.Date; +import java.util.UUID; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.TableGenerator; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + +import org.apache.cloudstack.storage.volume.VolumeState; +import org.apache.cloudstack.storage.volume.VolumeType; + +import com.cloud.api.Identity; +import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.utils.NumbersUtil; +import com.cloud.utils.db.GenericDao; + +@Entity +@Table(name = "volumes") +public class VolumeVO implements Identity { + @Id + @TableGenerator(name = "volume_sq", table = "sequence", pkColumnName = "name", valueColumnName = "value", pkColumnValue = "volume_seq", allocationSize = 1) + @GeneratedValue(strategy = GenerationType.TABLE) + @Column(name = "id") + long id; + + @Column(name = "name") + String name; + + @Column(name = "pool_id") + Long poolId; + + @Column(name = "last_pool_id") + Long lastPoolId; + + @Column(name = "account_id") + long accountId; + + @Column(name = "domain_id") + long domainId; + + @Column(name = "instance_id") + Long instanceId = null; + + @Column(name = "device_id") + Long deviceId = null; + + @Column(name = "size") + long size; + + @Column(name = "folder") + String folder; + + @Column(name = "path") + String path; + + @Column(name = "pod_id") + Long podId; + + @Column(name = "created") + Date created; + + @Column(name = "attached") + @Temporal(value = TemporalType.TIMESTAMP) + Date attached; + + @Column(name = "data_center_id") + long dataCenterId; + + @Column(name = "host_ip") + String hostip; + + @Column(name = "disk_offering_id") + long diskOfferingId; + + @Column(name = "template_id") + Long templateId; + + @Column(name = "first_snapshot_backup_uuid") + String firstSnapshotBackupUuid; + + @Column(name = "volume_type") + @Enumerated(EnumType.STRING) + VolumeType volumeType = VolumeType.UNKNOWN; + + @Column(name = "pool_type") + @Enumerated(EnumType.STRING) + StoragePoolType poolType; + + @Column(name = GenericDao.REMOVED_COLUMN) + Date removed; + + @Column(name = "updated") + @Temporal(value = TemporalType.TIMESTAMP) + Date updated; + + @Column(name="update_count", updatable = true, nullable=false) + protected long updatedCount; // This field should be updated everytime the state is updated. There's no set method in the vo object because it is done with in the dao code. + + @Column(name = "recreatable") + boolean recreatable; + + @Column(name = "state") + @Enumerated(value = EnumType.STRING) + private VolumeState state; + + @Column(name = "chain_info") + String chainInfo; + + @Column(name = "uuid") + String uuid; + + @Column(name="reservation") + String reservationId; + + // Real Constructor + public VolumeVO(VolumeType type, String name, long dcId, long domainId, long accountId, long diskOfferingId, long size) { + this.volumeType = type; + this.name = name; + this.dataCenterId = dcId; + this.accountId = accountId; + this.domainId = domainId; + this.size = size; + this.diskOfferingId = diskOfferingId; + this.state = VolumeState.Allocated; + this.uuid = UUID.randomUUID().toString(); + } + + public VolumeVO(String name, long dcId, long podId, long accountId, long domainId, Long instanceId, String folder, String path, long size, VolumeType vType) { + this.name = name; + this.accountId = accountId; + this.domainId = domainId; + this.instanceId = instanceId; + this.folder = folder; + this.path = path; + this.size = size; + this.podId = podId; + this.dataCenterId = dcId; + this.volumeType = vType; + this.state = VolumeState.Allocated; + this.recreatable = false; + this.uuid = UUID.randomUUID().toString(); + } + + // Copy Constructor + public VolumeVO(VolumeVO that) { + this(that.getName(), that.getDataCenterId(), that.getPodId(), that.getAccountId(), that.getDomainId(), that.getInstanceId(), that.getFolder(), that.getPath(), that.getSize(), that + .getVolumeType()); + this.recreatable = that.isRecreatable(); + this.state = that.getState(); + this.size = that.getSize(); + this.diskOfferingId = that.getDiskOfferingId(); + this.poolId = that.getPoolId(); + this.attached = that.getAttached(); + this.chainInfo = that.getChainInfo(); + this.templateId = that.getTemplateId(); + this.deviceId = that.getDeviceId(); + this.uuid = UUID.randomUUID().toString(); + } + + public long getUpdatedCount() { + return this.updatedCount; + } + + public void incrUpdatedCount() { + this.updatedCount++; + } + + public void decrUpdatedCount() { + this.updatedCount--; + } + + public boolean isRecreatable() { + return recreatable; + } + + public void setRecreatable(boolean recreatable) { + this.recreatable = recreatable; + } + + public long getId() { + return id; + } + + + public Long getPodId() { + return podId; + } + + + public long getDataCenterId() { + return dataCenterId; + } + + public String getName() { + return name; + } + + public long getAccountId() { + return accountId; + } + + public void setPoolType(StoragePoolType poolType) { + this.poolType = poolType; + } + + public StoragePoolType getPoolType() { + return poolType; + } + + public long getDomainId() { + return domainId; + } + + public String getFolder() { + return folder; + } + + public String getPath() { + return path; + } + + protected VolumeVO() { + } + + public long getSize() { + return size; + } + + public void setSize(long size) { + this.size = size; + } + + public Long getInstanceId() { + return instanceId; + } + + public Long getDeviceId() { + return deviceId; + } + + public void setDeviceId(Long deviceId) { + this.deviceId = deviceId; + } + + public VolumeType getVolumeType() { + return volumeType; + } + + public void setName(String name) { + this.name = name; + } + + public void setFolder(String folder) { + this.folder = folder; + } + + public void setAccountId(long accountId) { + this.accountId = accountId; + } + + public void setDomainId(long domainId) { + this.domainId = domainId; + } + + public void setInstanceId(Long instanceId) { + this.instanceId = instanceId; + } + + public void setPath(String path) { + this.path = path; + } + + public String getHostIp() { + return hostip; + } + + public void setHostIp(String hostip) { + this.hostip = hostip; + } + + public void setPodId(Long podId) { + this.podId = podId; + } + + public void setDataCenterId(long dataCenterId) { + this.dataCenterId = dataCenterId; + } + + public void setVolumeType(VolumeType type) { + volumeType = type; + } + + public Date getCreated() { + return created; + } + + public Date getRemoved() { + return removed; + } + + public void setRemoved(Date removed) { + this.removed = removed; + } + + public long getDiskOfferingId() { + return diskOfferingId; + } + + public void setDiskOfferingId(long diskOfferingId) { + this.diskOfferingId = diskOfferingId; + } + + public Long getTemplateId() { + return templateId; + } + + public void setTemplateId(Long templateId) { + this.templateId = templateId; + } + + public String getFirstSnapshotBackupUuid() { + return firstSnapshotBackupUuid; + } + + public void setFirstSnapshotBackupUuid(String firstSnapshotBackupUuid) { + this.firstSnapshotBackupUuid = firstSnapshotBackupUuid; + } + + public Long getPoolId() { + return poolId; + } + + public void setPoolId(Long poolId) { + this.poolId = poolId; + } + + public Date getUpdated() { + return updated; + } + + public VolumeState getState() { + return state; + } + + public void setUpdated(Date updated) { + this.updated = updated; + } + + @Override + public String toString() { + return new StringBuilder("Vol[").append(id).append("|vm=").append(instanceId).append("|").append(volumeType).append("]").toString(); + } + + public Date getAttached() { + return this.attached; + } + + public void setAttached(Date attached) { + this.attached = attached; + } + + public String getChainInfo() { + return this.chainInfo; + } + + public void setChainInfo(String chainInfo) { + this.chainInfo = chainInfo; + } + + public Long getLastPoolId() { + return this.lastPoolId; + } + + public void setLastPoolId(Long poolId) { + this.lastPoolId = poolId; + } + + @Override + public int hashCode() { + return NumbersUtil.hash(id); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof VolumeVO) { + return id == ((VolumeVO) obj).id; + } else { + return false; + } + } + + public String getReservationId() { + return this.reservationId; + } + + public void setReservationId(String reserv) { + this.reservationId = reserv; + } + + @Override + public String getUuid() { + return this.uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } +} + diff --git a/platform/storage/test/org/apache/cloudstack/storage/test/AopTest.java b/platform/storage/test/org/apache/cloudstack/storage/test/AopTest.java new file mode 100644 index 00000000000..0c2a2adf061 --- /dev/null +++ b/platform/storage/test/org/apache/cloudstack/storage/test/AopTest.java @@ -0,0 +1,14 @@ +package org.apache.cloudstack.storage.test; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Target({TYPE, METHOD}) +@Retention(RUNTIME) +public @interface AopTest { + +} diff --git a/platform/storage/test/org/apache/cloudstack/storage/test/AopTestAdvice.java b/platform/storage/test/org/apache/cloudstack/storage/test/AopTestAdvice.java new file mode 100644 index 00000000000..9bdec741eb1 --- /dev/null +++ b/platform/storage/test/org/apache/cloudstack/storage/test/AopTestAdvice.java @@ -0,0 +1,20 @@ +package org.apache.cloudstack.storage.test; + +import org.aspectj.lang.ProceedingJoinPoint; + +import com.cloud.utils.db.Transaction; + +public class AopTestAdvice { + public Object AopTestMethod(ProceedingJoinPoint call) throws Throwable { + Transaction txn = Transaction.open(call.getSignature().getName()); + System.out.println(call.getSignature().getName()); + Object ret = null; + try { + ret = call.proceed(); + } finally { + txn.close(); + } + System.out.println("end"); + return ret; + } +} diff --git a/platform/storage/test/org/apache/cloudstack/storage/test/StorageFactoryBean.java b/platform/storage/test/org/apache/cloudstack/storage/test/StorageFactoryBean.java new file mode 100644 index 00000000000..68952b17f9e --- /dev/null +++ b/platform/storage/test/org/apache/cloudstack/storage/test/StorageFactoryBean.java @@ -0,0 +1,42 @@ +package org.apache.cloudstack.storage.test; + + +import org.mockito.Mockito; +import org.springframework.beans.factory.FactoryBean; + +/** + * A {@link FactoryBean} for creating mocked beans based on Mockito so that they + * can be {@link @Autowired} into Spring test configurations. + * + * @author Mattias Severson, Jayway + * + * @see FactoryBean + * @see org.mockito.Mockito + */ +public class StorageFactoryBean implements FactoryBean { + + private Class classToBeMocked; + + /** + * Creates a Mockito mock instance of the provided class. + * @param classToBeMocked The class to be mocked. + */ + public StorageFactoryBean(Class classToBeMocked) { + this.classToBeMocked = classToBeMocked; + } + + @Override + public T getObject() throws Exception { + return Mockito.mock(classToBeMocked); + } + + @Override + public Class getObjectType() { + return classToBeMocked; + } + + @Override + public boolean isSingleton() { + return true; + } +} diff --git a/platform/storage/test/org/apache/cloudstack/storage/test/storageContext.xml b/platform/storage/test/org/apache/cloudstack/storage/test/storageContext.xml index 35d18a6b9e7..508848a7428 100644 --- a/platform/storage/test/org/apache/cloudstack/storage/test/storageContext.xml +++ b/platform/storage/test/org/apache/cloudstack/storage/test/storageContext.xml @@ -1,11 +1,66 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/platform/storage/test/org/apache/cloudstack/storage/test/volumeServiceTest.java b/platform/storage/test/org/apache/cloudstack/storage/test/volumeServiceTest.java index 39df0c53a97..8734d5332e4 100644 --- a/platform/storage/test/org/apache/cloudstack/storage/test/volumeServiceTest.java +++ b/platform/storage/test/org/apache/cloudstack/storage/test/volumeServiceTest.java @@ -20,21 +20,61 @@ package org.apache.cloudstack.storage.test; import static org.junit.Assert.*; +import java.awt.List; +import java.util.LinkedList; + +import javax.inject.Inject; + +import org.apache.cloudstack.storage.volume.VolumeMotionService; import org.apache.cloudstack.storage.volume.VolumeService; +import org.apache.cloudstack.storage.volume.db.VolumeDao; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.mockito.Mockito.*; + + +import com.cloud.utils.db.DB; + @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations="storageContext.xml") public class volumeServiceTest { @Autowired protected VolumeService volService; + @Inject + protected VolumeDao volumeDao; + @Autowired + protected VolumeMotionService vmotion; + + @Before + public void setUp() { + Mockito.when(vmotion.copyVolume(null, null)).thenReturn(false); + } + @Test + @DB public void test() { - assertTrue(volService.deleteVolume(1) == false); + assertTrue(volService.deleteVolume(1) != false); + assertNotNull(volumeDao); + //VolumeVO vol = new VolumeVO(Volume.Type.DATADISK, "test", 1, 2, 2, 1, 1); + //volumeDao.persist(vol); + /* + VolumeVO volume = new VolumeVO(); + String name = "test"; + long size = 100; + volume.setName(name); + volume.setSize(size); + volumeDao.persist(volume); + VolumeVO newVol = volumeDao.getVolumeByName(name); + assertTrue(newVol.getSize() == volume.getSize()); + */ + fail("Not yet implemented"); } } diff --git a/pom.xml b/pom.xml index ff4b9eebcc6..9a633a12fc3 100644 --- a/pom.xml +++ b/pom.xml @@ -79,7 +79,7 @@ 2.4 1.2 1.0-20081010.060147 - 3.0.5.RELEASE + 3.1.2.RELEASE true diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index aa8aeb8e326..aa5867fc4ea 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -1500,6 +1500,7 @@ CREATE TABLE `cloud`.`storage_pool` ( `created` datetime COMMENT 'date the pool created', `removed` datetime COMMENT 'date removed if not null', `update_time` DATETIME, + `storage_provider` varchar(255) NOT NULL, `status` varchar(32), PRIMARY KEY (`id`), CONSTRAINT `fk_storage_pool__pod_id` FOREIGN KEY `fk_storage_pool__pod_id` (`pod_id`) REFERENCES `host_pod_ref` (`id`) ON DELETE CASCADE,