@DB works on spring

This commit is contained in:
Edison Su 2012-10-25 10:26:49 -07:00
parent f92ce72639
commit ad3e98c1eb
20 changed files with 1311 additions and 381 deletions

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>platform-storage</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -1,21 +1,13 @@
<!--
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.
-->
<!-- 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. -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
@ -48,6 +40,37 @@
<artifactId>cloud-platform-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.openjpa</groupId>
<artifactId>openjpa</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${cs.mysql.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
</dependencies>
<build>
<defaultGoal>install</defaultGoal>

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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<VolumeState>{
private VolumeVO volumeVO;
@Override
public VolumeState getState() {
// TODO Auto-generated method stub
return null;
}
}

View File

@ -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;
}

View File

@ -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());
}

View File

@ -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;
}
}

View File

@ -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<VolumeState, VolumeEvent, Volume> getStateMachine() {
return s_fsm;
}
public String getDescription() {
return _description;
}
private final static StateMachine2<VolumeState, VolumeEvent, Volume> s_fsm = new StateMachine2<VolumeState, VolumeEvent, Volume>();
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);
}
}

View File

@ -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
}

View File

@ -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<VolumeVO, Long>, StateDao<VolumeState, VolumeEvent, VolumeVO> {
List<VolumeVO> findDetachedByAccount(long accountId);
List<VolumeVO> findByAccount(long accountId);
Pair<Long, Long> getCountAndTotalByPool(long poolId);
Pair<Long, Long> getNonDestroyedCountAndTotalByPool(long poolId);
List<VolumeVO> findByInstance(long id);
List<VolumeVO> findByInstanceAndType(long id, VolumeType vType);
List<VolumeVO> findByInstanceIdDestroyed(long vmId);
List<VolumeVO> findByAccountAndPod(long accountId, long podId);
List<VolumeVO> 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<VolumeVO> findCreatedByInstance(long id);
List<VolumeVO> findByPoolId(long poolId);
List<VolumeVO> findByInstanceAndDeviceId(long instanceId, long deviceId);
List<VolumeVO> findUsableVolumesForInstance(long instanceId);
Long countAllocatedVolumesForAccount(long accountId);
HypervisorType getHypervisorType(long volumeId);
List<VolumeVO> listVolumesToBeDestroyed();
ImageFormat getImageFormat(Long volumeId);
List<VolumeVO> findReadyRootVolumesByInstance(long instanceId);
List<Long> listPoolIdsByVolumeCount(long dcId, Long podId, Long clusterId, long accountId);
}

View File

@ -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<VolumeVO, Long> implements VolumeDao {
private static final Logger s_logger = Logger.getLogger(VolumeDaoImpl.class);
protected final SearchBuilder<VolumeVO> DetachedAccountIdSearch;
protected final SearchBuilder<VolumeVO> TemplateZoneSearch;
protected final GenericSearchBuilder<VolumeVO, SumCount> TotalSizeByPoolSearch;
protected final GenericSearchBuilder<VolumeVO, Long> ActiveTemplateSearch;
protected final SearchBuilder<VolumeVO> InstanceStatesSearch;
protected final SearchBuilder<VolumeVO> AllFieldsSearch;
protected GenericSearchBuilder<VolumeVO, Long> 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<VolumeVO> findDetachedByAccount(long accountId) {
SearchCriteria<VolumeVO> sc = DetachedAccountIdSearch.create();
sc.setParameters("accountId", accountId);
sc.setParameters("destroyed", VolumeState.Destroy);
return listBy(sc);
}
@Override
public List<VolumeVO> findByAccount(long accountId) {
SearchCriteria<VolumeVO> sc = AllFieldsSearch.create();
sc.setParameters("accountId", accountId);
sc.setParameters("state", VolumeState.Ready);
return listBy(sc);
}
@Override
public List<VolumeVO> findByInstance(long id) {
SearchCriteria<VolumeVO> sc = AllFieldsSearch.create();
sc.setParameters("instanceId", id);
return listBy(sc);
}
@Override
public List<VolumeVO> findByInstanceAndDeviceId(long instanceId, long deviceId){
SearchCriteria<VolumeVO> sc = AllFieldsSearch.create();
sc.setParameters("instanceId", instanceId);
sc.setParameters("deviceId", deviceId);
return listBy(sc);
}
@Override
public List<VolumeVO> findByPoolId(long poolId) {
SearchCriteria<VolumeVO> sc = AllFieldsSearch.create();
sc.setParameters("poolId", poolId);
sc.setParameters("notDestroyed", VolumeState.Destroy);
sc.setParameters("vType", VolumeType.ROOT.toString());
return listBy(sc);
}
@Override
public List<VolumeVO> findCreatedByInstance(long id) {
SearchCriteria<VolumeVO> sc = AllFieldsSearch.create();
sc.setParameters("instanceId", id);
sc.setParameters("state", VolumeState.Ready);
return listBy(sc);
}
@Override
public List<VolumeVO> findUsableVolumesForInstance(long instanceId) {
SearchCriteria<VolumeVO> sc = InstanceStatesSearch.create();
sc.setParameters("instance", instanceId);
sc.setParameters("states", VolumeState.Creating, VolumeState.Ready, VolumeState.Allocated);
return listBy(sc);
}
@Override
public List<VolumeVO> findByInstanceAndType(long id, VolumeType vType) {
SearchCriteria<VolumeVO> sc = AllFieldsSearch.create();
sc.setParameters("instanceId", id);
sc.setParameters("vType", vType.toString());
return listBy(sc);
}
@Override
public List<VolumeVO> findByInstanceIdDestroyed(long vmId) {
SearchCriteria<VolumeVO> sc = AllFieldsSearch.create();
sc.setParameters("instanceId", vmId);
sc.setParameters("destroyed", VolumeState.Destroy);
return listBy(sc);
}
@Override
public List<VolumeVO> findReadyRootVolumesByInstance(long instanceId) {
SearchCriteria<VolumeVO> sc = AllFieldsSearch.create();
sc.setParameters("instanceId", instanceId);
sc.setParameters("state", VolumeState.Ready);
sc.setParameters("vType", VolumeType.ROOT);
return listBy(sc);
}
@Override
public List<VolumeVO> findByAccountAndPod(long accountId, long podId) {
SearchCriteria<VolumeVO> sc = AllFieldsSearch.create();
sc.setParameters("accountId", accountId);
sc.setParameters("pod", podId);
sc.setParameters("state", VolumeState.Ready);
return listIncludingRemovedBy(sc);
}
@Override
public List<VolumeVO> findByTemplateAndZone(long templateId, long zoneId) {
SearchCriteria<VolumeVO> sc = TemplateZoneSearch.create();
sc.setParameters("template", templateId);
sc.setParameters("zone", zoneId);
return listIncludingRemovedBy(sc);
}
@Override
public boolean isAnyVolumeActivelyUsingTemplateOnPool(long templateId, long poolId) {
SearchCriteria<Long> sc = ActiveTemplateSearch.create();
sc.setParameters("template", templateId);
sc.setParameters("pool", poolId);
List<Long> 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<VolumeVO> 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<Long, Long> getCountAndTotalByPool(long poolId) {
SearchCriteria<SumCount> sc = TotalSizeByPoolSearch.create();
sc.setParameters("poolId", poolId);
List<SumCount> results = customSearch(sc, null);
SumCount sumCount = results.get(0);
return new Pair<Long, Long>(sumCount.count, sumCount.sum);
}
@Override
public Long countAllocatedVolumesForAccount(long accountId) {
SearchCriteria<Long> 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<VolumeVO> listVolumesToBeDestroyed() {
SearchCriteria<VolumeVO> 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<VolumeVO> 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<Long> listPoolIdsByVolumeCount(long dcId, Long podId, Long clusterId, long accountId) {
Transaction txn = Transaction.currentTxn();
PreparedStatement pstmt = null;
List<Long> result = new ArrayList<Long>();
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<Long, Long> getNonDestroyedCountAndTotalByPool(long poolId) {
SearchCriteria<SumCount> sc = TotalSizeByPoolSearch.create();
sc.setParameters("poolId", poolId);
sc.setParameters("state", VolumeState.Destroy);
List<SumCount> results = customSearch(sc, null);
SumCount sumCount = results.get(0);
return new Pair<Long, Long>(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;
}
}

View File

@ -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;
}
}

View File

@ -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 {
}

View File

@ -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;
}
}

View File

@ -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<T> implements FactoryBean<T> {
private Class<T> classToBeMocked;
/**
* Creates a Mockito mock instance of the provided class.
* @param classToBeMocked The class to be mocked.
*/
public StorageFactoryBean(Class<T> 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;
}
}

View File

@ -1,11 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<context:annotation-config />
<context:component-scan base-package="org.apache.cloudstack.storage" />
<context:component-scan base-package="com.cloud.utils.db" />
<context:component-scan base-package="com.cloud.storage.dao" />
<context:component-scan base-package=" com.cloud.upgrade.dao" />
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="aopTestBean" class="org.apache.cloudstack.storage.test.AopTestAdvice"/>
<aop:config proxy-target-class="true" >
<aop:aspect id="AopTestAdvice" ref="aopTestBean">
<aop:pointcut id="aoptest"
expression="@annotation(com.cloud.utils.db.DB)" />
<aop:around pointcut-ref="aoptest" method="AopTestMethod"/>
</aop:aspect>
</aop:config>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/cloud" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
<bean id="openJpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="databasePlatform"
value="org.apache.openjpa.jdbc.sql.MySQLDictionary" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="openJpaVendorAdapter" />
<property name="packagesToScan" value="org.apache.cloudstack.storage" />
</bean>
<bean id="sharedEntityManager"
class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="someDependencyMock" class="org.apache.cloudstack.storage.test.StorageFactoryBean">
<constructor-arg name="classToBeMocked"
value="org.apache.cloudstack.storage.volume.VolumeMotionService" />
</bean>
</beans>

View File

@ -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");
}
}

View File

@ -79,7 +79,7 @@
<cs.servlet.version>2.4</cs.servlet.version>
<cs.jstl.version>1.2</cs.jstl.version>
<cs.selenium.server.version>1.0-20081010.060147</cs.selenium.server.version>
<org.springframework.version>3.0.5.RELEASE</org.springframework.version>
<org.springframework.version>3.1.2.RELEASE</org.springframework.version>
<skipTests>true</skipTests>
</properties>

View File

@ -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,