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,