create data volume is splitted into two stage:

1. create a volume entry in the database,
2. when user attaching the volume to a VM, then actually create the volume on storage pool.
This commit is contained in:
edison 2010-09-21 17:59:38 -07:00
parent abba8398b3
commit 6fc7528809
12 changed files with 119 additions and 23 deletions

View File

@ -18,6 +18,7 @@
package com.cloud.vm;
import com.cloud.offering.DiskOffering;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.storage.Volume;
/**
@ -38,6 +39,7 @@ public class DiskProfile {
private long volumeId;
private Volume vol;
private DiskOffering offering;
private HypervisorType hyperType;
protected DiskProfile() {
}
@ -128,4 +130,12 @@ public class DiskProfile {
public String toString() {
return new StringBuilder("DskChr[").append(type).append("|").append(size).append("|").append("]").toString();
}
public void setHyperType(HypervisorType hyperType) {
this.hyperType = hyperType;
}
public HypervisorType getHypersorType() {
return this.hyperType;
}
}

View File

@ -489,7 +489,8 @@ public interface ManagementServer {
* @param hyperType - hypervisor type
* @return true if success, false if not
*/
VolumeVO createVolume(long accountId, long userId, String name, long zoneId, long diskOfferingId, long startEventId, long size) throws InternalErrorException;
VolumeVO allocVolume(long accountId, long userId, String name, long zoneId, long diskOfferingId, long startEventId, long size) throws InternalErrorException;
long createVolumeAsync(long userId, long accountId, String name, long zoneId, long diskOfferingId, long size) throws InvalidParameterValueException, InternalErrorException, ResourceAllocationException;
/**

View File

@ -213,7 +213,9 @@ public interface StorageManager extends Manager {
* @param size
* @return VolumeVO
*/
VolumeVO createVolume(long accountId, long userId, String name, DataCenterVO dc, DiskOfferingVO diskOffering, long startEventId, long size);
VolumeVO createVolume(long volumeId, HypervisorType hyperType);
VolumeVO allocVolume(long accountId, long userId, String name, DataCenterVO dc, DiskOfferingVO diskOffering, long startEventId, long size);
/**
* Marks the specified volume as destroyed in the management server database. The expunge thread will delete the volume from its storage pool.

View File

@ -471,6 +471,10 @@ public class VolumeVO implements Volume {
public State getState() {
return state;
}
public void setState(State st) {
this.state = st;
}
public void setUpdated(Date updated) {
this.updated = updated;

View File

@ -33,6 +33,7 @@ import com.cloud.exception.ResourceAllocationException;
import com.cloud.serializer.SerializerHelper;
import com.cloud.server.ManagementServer;
import com.cloud.storage.StoragePoolVO;
import com.cloud.storage.Volume;
import com.cloud.storage.VolumeVO;
import com.cloud.utils.Pair;

View File

@ -30,6 +30,7 @@ import com.cloud.async.AsyncJobVO;
import com.cloud.domain.DomainVO;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.server.Criteria;
import com.cloud.storage.Volume;
import com.cloud.storage.VolumeVO;
import com.cloud.user.Account;
import com.cloud.utils.Pair;
@ -208,7 +209,12 @@ public class ListVolumesCmd extends BaseCmd{
String storageType;
try {
if(volume.getPoolId() == null){
storageType = "unknown";
if (volume.getState() == Volume.State.Allocated) {
/*set it as shared, so the UI can attach it to VM*/
storageType = "shared";
} else {
storageType = "unknown";
}
} else {
storageType = getManagementServer().volumeIsOnSharedStorage(volume.getId()) ? "shared" : "local";
}
@ -228,7 +234,7 @@ public class ListVolumesCmd extends BaseCmd{
volumeData.add(new Pair<String, Object>(BaseCmd.Properties.SOURCE_ID.getName(),volume.getSourceId()));
volumeData.add(new Pair<String, Object>(BaseCmd.Properties.SOURCE_TYPE.getName(),volume.getSourceType().toString()));
volumeData.add(new Pair<String, Object>(BaseCmd.Properties.HYPERVISOR_TYPE.getName(), getManagementServer().getVolumeHyperType(volume.getId())));
volumeData.add(new Pair<String, Object>(BaseCmd.Properties.HYPERVISOR.getName(), getManagementServer().getVolumeHyperType(volume.getId())));
vTag[i++] = volumeData;
}

View File

@ -62,7 +62,7 @@ public class VolumeOperationExecutor extends BaseAsyncJobExecutor {
if (op == VolumeOp.Create) {
eventType = EventTypes.EVENT_VOLUME_CREATE;
failureDescription = "Failed to create volume";
volume = asyncMgr.getExecutorContext().getManagementServer().createVolume(param.getUserId(), param.getAccountId(), param.getName(), param.getZoneId(), param.getDiskOfferingId(), param.getEventId(), param.getSize());
volume = asyncMgr.getExecutorContext().getManagementServer().allocVolume(param.getUserId(), param.getAccountId(), param.getName(), param.getZoneId(), param.getDiskOfferingId(), param.getEventId(), param.getSize());
if (volume.getStatus() == AsyncInstanceCreateStatus.Corrupted) {
asyncMgr.completeAsyncJob(getJob().getId(), AsyncJobResult.STATUS_FAILED, BaseCmd.INTERNAL_ERROR, "Failed to create volume.");
} else {

View File

@ -195,6 +195,7 @@ import com.cloud.storage.GuestOSCategoryVO;
import com.cloud.storage.GuestOSVO;
import com.cloud.storage.LaunchPermissionVO;
import com.cloud.storage.Snapshot;
import com.cloud.storage.Volume;
import com.cloud.storage.Snapshot.SnapshotType;
import com.cloud.storage.SnapshotPolicyVO;
import com.cloud.storage.SnapshotScheduleVO;
@ -1770,14 +1771,14 @@ public class ManagementServerImpl implements ManagementServer {
}
@Override
public VolumeVO createVolume(long userId, long accountId, String name, long zoneId, long diskOfferingId, long startEventId, long size) throws InternalErrorException {
public VolumeVO allocVolume(long userId, long accountId, String name, long zoneId, long diskOfferingId, long startEventId, long size) throws InternalErrorException {
saveStartedEvent(userId, accountId, EventTypes.EVENT_VOLUME_CREATE, "Creating volume", startEventId);
DataCenterVO zone = _dcDao.findById(zoneId);
DiskOfferingVO diskOffering = _diskOfferingDao.findById(diskOfferingId);
VolumeVO createdVolume = _storageMgr.createVolume(accountId, userId, name, zone, diskOffering, startEventId,size);
VolumeVO allocatedVolume = _storageMgr.allocVolume(accountId, userId, name, zone, diskOffering, startEventId,size);
if (createdVolume != null)
return createdVolume;
if (allocatedVolume != null)
return allocatedVolume;
else
throw new InternalErrorException("Failed to create volume.");
}
@ -1898,7 +1899,7 @@ public class ManagementServerImpl implements ManagementServer {
}
// Check that the volume is stored on shared storage
if (!_storageMgr.volumeOnSharedStoragePool(volume)) {
if (volume.getState() != Volume.State.Allocated && !_storageMgr.volumeOnSharedStoragePool(volume)) {
throw new InvalidParameterValueException("Please specify a volume that has been created on a shared storage pool.");
}
@ -1981,7 +1982,7 @@ public class ManagementServerImpl implements ManagementServer {
}
// Check that the volume is stored on shared storage
if (!_storageMgr.volumeOnSharedStoragePool(volume)) {
if (!volume.getState().equals(Volume.State.Allocated) && !_storageMgr.volumeOnSharedStoragePool(volume)) {
throw new InvalidParameterValueException("Please specify a volume that has been created on a shared storage pool.");
}
@ -6846,6 +6847,9 @@ public class ManagementServerImpl implements ManagementServer {
if (volume.getStatus() != AsyncInstanceCreateStatus.Created) {
throw new InvalidParameterValueException("VolumeId: " + volumeId + " is not in Created state but " + volume.getStatus() + ". Cannot take snapshot.");
}
if (volume.getState() == Volume.State.Allocated) {
throw new InvalidParameterValueException("VolumeId: " + volumeId + " is not Created, need to attach it to vm at first, then you can take snapshot.");
}
StoragePoolVO storagePoolVO = findPoolById(volume.getPoolId());
if (storagePoolVO == null) {
throw new InvalidParameterValueException("VolumeId: " + volumeId + " does not have a valid storage pool. Is it destroyed?");
@ -8340,6 +8344,10 @@ public class ManagementServerImpl implements ManagementServer {
throw new InvalidParameterValueException("maxSnaps exceeds limit: "+ intervalMaxSnaps +" for interval type: " + intervalType);
}
if(_volumeDao.findById(volumeId).getState() == Volume.State.Allocated) {
throw new InvalidParameterValueException("Cant create snapshot policy on this volume, pls attach it to a VM at first");
}
return _snapMgr.createPolicy(userId, accountId, volumeId, schedule, (short)type.ordinal() , maxSnaps, timezoneId);
}

View File

@ -339,7 +339,7 @@ public class StorageManagerImpl implements StorageManager {
} else {
offering = _offeringDao.findById(vol.getDiskOfferingId());
}
VolumeVO created = createVolume(create, vm, template, dc, pod, host.getClusterId(), offering, diskOffering, new ArrayList<StoragePoolVO>(),0);
VolumeVO created = createVolume(create, vm, template, dc, pod, host.getClusterId(), offering, diskOffering, new ArrayList<StoragePoolVO>(),0, template.getHypervisorType());
if (created == null) {
break;
}
@ -721,7 +721,7 @@ public class StorageManagerImpl implements StorageManager {
@DB
public VolumeVO createVolume(VolumeVO volume, VMInstanceVO vm, VMTemplateVO template, DataCenterVO dc, HostPodVO pod, Long clusterId,
ServiceOfferingVO offering, DiskOfferingVO diskOffering, List<StoragePoolVO> avoids, long size) {
ServiceOfferingVO offering, DiskOfferingVO diskOffering, List<StoragePoolVO> avoids, long size, HypervisorType hyperType) {
StoragePoolVO pool = null;
final HashSet<StoragePool> avoidPools = new HashSet<StoragePool>(avoids);
@ -731,6 +731,7 @@ public class StorageManagerImpl implements StorageManager {
} else {
dskCh = createDiskCharacteristics(volume, template, dc, diskOffering);
}
dskCh.setHyperType(hyperType);
Transaction txn = Transaction.currentTxn();
@ -810,6 +811,7 @@ public class StorageManagerImpl implements StorageManager {
volume.setSize(created.getSize());
volume.setPoolType(pool.getPoolType());
volume.setPodId(pod.getId());
volume.setState(Volume.State.Created);
_volsDao.persist(volume);
return volume;
}
@ -867,7 +869,7 @@ public class StorageManagerImpl implements StorageManager {
VolumeVO dataCreated = null;
VolumeVO rootCreated = null;
try {
rootCreated = createVolume(rootVol, vm, template, dc, pod, null, offering, diskOffering, avoids,size);
rootCreated = createVolume(rootVol, vm, template, dc, pod, null, offering, diskOffering, avoids,size, template.getHypervisorType());
if (rootCreated == null) {
throw new CloudRuntimeException("Unable to create " + rootVol);
}
@ -876,7 +878,7 @@ public class StorageManagerImpl implements StorageManager {
if (dataVol != null) {
StoragePoolVO pool = _storagePoolDao.findById(rootCreated.getPoolId());
dataCreated = createVolume(dataVol, vm, null, dc, pod, pool.getClusterId(), offering, diskOffering, avoids,size);
dataCreated = createVolume(dataVol, vm, null, dc, pod, pool.getClusterId(), offering, diskOffering, avoids,size, template.getHypervisorType());
if (dataCreated == null) {
throw new CloudRuntimeException("Unable to create " + dataVol);
}
@ -1576,7 +1578,7 @@ public class StorageManagerImpl implements StorageManager {
@Override
@DB
public VolumeVO createVolume(long accountId, long userId, String userSpecifiedName, DataCenterVO dc, DiskOfferingVO diskOffering, long startEventId, long size)
public VolumeVO createVolume(long volumeId, HypervisorType hyperType)
{
String volumeName = "";
VolumeVO createdVolume = null;
@ -1619,9 +1621,12 @@ public class StorageManagerImpl implements StorageManager {
List<StoragePoolVO> poolsToAvoid = new ArrayList<StoragePoolVO>();
Set<Long> podsToAvoid = new HashSet<Long>();
Pair<HostPodVO, Long> pod = null;
while ((pod = _agentMgr.findPod(null, null, dc, account.getId(), podsToAvoid)) != null) {
if ((createdVolume = createVolume(volume, null, null, dc, pod.first(), null, null, diskOffering, poolsToAvoid, size)) != null) {
DataCenterVO dc = _dcDao.findById(volume.getDataCenterId());
DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId());
long accountId = volume.getAccountId();
while ((pod = _agentMgr.findPod(null, null, dc, volume.getAccountId(), podsToAvoid)) != null) {
if ((createdVolume = createVolume(volume, null, null, dc, pod.first(), null, null, diskOffering, poolsToAvoid, volume.getSize(), hyperType)) != null) {
break;
} else {
podsToAvoid.add(pod.first().getId());
@ -1631,9 +1636,7 @@ public class StorageManagerImpl implements StorageManager {
// Create an event
EventVO event = new EventVO();
event.setAccountId(accountId);
event.setUserId(userId);
event.setType(EventTypes.EVENT_VOLUME_CREATE);
event.setStartId(startEventId);
event.setType(EventTypes.EVENT_VOLUME_CREATE);
Transaction txn = Transaction.currentTxn();
@ -1665,6 +1668,56 @@ public class StorageManagerImpl implements StorageManager {
return createdVolume;
}
@Override
@DB
public VolumeVO allocVolume(long accountId, long userId, String userSpecifiedName, DataCenterVO dc, DiskOfferingVO diskOffering, long startEventId, long size) {
String volumeName = "";
VolumeVO createdVolume = null;
try
{
// Determine the volume's name
volumeName = getRandomVolumeName();
// Create the Volume object and save it so that we can return it to the user
Account account = _accountDao.findById(accountId);
VolumeVO volume = new VolumeVO(userSpecifiedName, -1, -1, -1, -1, new Long(-1), null, null, 0, Volume.VolumeType.DATADISK);
volume.setPoolId(null);
volume.setDataCenterId(dc.getId());
volume.setPodId(null);
volume.setAccountId(accountId);
volume.setDomainId(account.getDomainId());
volume.setMirrorState(MirrorState.NOT_MIRRORED);
volume.setDiskOfferingId(diskOffering.getId());
volume.setStorageResourceType(Storage.StorageResourceType.STORAGE_POOL);
volume.setInstanceId(null);
volume.setUpdated(new Date());
volume.setStatus(AsyncInstanceCreateStatus.Created);
volume.setDomainId(account.getDomainId());
volume.setSourceId(diskOffering.getId());
volume.setSourceType(SourceType.DiskOffering);
volume.setState(Volume.State.Allocated);
volume = _volsDao.persist(volume);
AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor.getCurrentExecutor();
if (asyncExecutor != null) {
AsyncJobVO job = asyncExecutor.getJob();
if (s_logger.isInfoEnabled())
s_logger.info("CreateVolume created a new instance " + volume.getId() + ", update async job-" + job.getId() + " progress status");
_asyncMgr.updateAsyncJobAttachment(job.getId(), "volume", volume.getId());
_asyncMgr.updateAsyncJobStatus(job.getId(), BaseCmd.PROGRESS_INSTANCE_CREATED, volume.getId());
}
createdVolume = volume;
} catch (Exception e) {
s_logger.error("Unhandled exception while saving volume " + volumeName, e);
}
return createdVolume;
}
@Override
@DB

View File

@ -150,7 +150,7 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement
// refine the logic of checking hypervisorType based on offering info
Long clusterId = pool.getClusterId();
ClusterVO cluster = _clusterDao.findById(clusterId);
if (!(cluster.getHypervisorType() == template.getHypervisorType())) {
if (!(cluster.getHypervisorType() == dskCh.getHypersorType())) {
return false;
}

View File

@ -311,6 +311,13 @@ public class UserVmManagerImpl implements UserVmManager {
} else {
rootVolumeOfVm = rootVolumesOfVm.get(0);
}
if (volume.getState().equals(Volume.State.Allocated)) {
/*Need to create the volume*/
volume = _storageMgr.createVolume(volumeId, _volsDao.getHypervisorType(rootVolumeOfVm.getId()));
}
List<VolumeVO> vols = _volsDao.findByInstance(vmId);
if( deviceId != null ) {
if( deviceId.longValue() > 15 || deviceId.longValue() == 0 || deviceId.longValue() == 3) {

View File

@ -149,8 +149,12 @@ function showTemplatesTab() {
var formatSelect = $("#add_template_format").empty();
if (getHypervisorType() == "kvm") {
formatSelect.append("<option value='QCOW2'>QCOW2</option>");
formatSelect.append("<option value='VHD'>VHD</option>");
formatSelect.append("<option value='OVA'>OVA</option>");
} else if (getHypervisorType() == "xenserver") {
formatSelect.append("<option value='VHD'>VHD</option>");
formatSelect.append("<option value='QCOW2'>QCOW2</option>");
formatSelect.append("<option value='OVA'>OVA</option>");
}
$("#template_action_new").bind("click", function(event) {