mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
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:
parent
abba8398b3
commit
6fc7528809
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
/**
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user