diff --git a/api/src/com/cloud/vm/DiskProfile.java b/api/src/com/cloud/vm/DiskProfile.java index cad858b9dad..af8f2afb42d 100644 --- a/api/src/com/cloud/vm/DiskProfile.java +++ b/api/src/com/cloud/vm/DiskProfile.java @@ -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; + } } diff --git a/core/src/com/cloud/server/ManagementServer.java b/core/src/com/cloud/server/ManagementServer.java index 3e9188e2bc4..78bc14f00b4 100755 --- a/core/src/com/cloud/server/ManagementServer.java +++ b/core/src/com/cloud/server/ManagementServer.java @@ -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; /** diff --git a/core/src/com/cloud/storage/StorageManager.java b/core/src/com/cloud/storage/StorageManager.java index 88b99753f50..753d7d370ad 100755 --- a/core/src/com/cloud/storage/StorageManager.java +++ b/core/src/com/cloud/storage/StorageManager.java @@ -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. diff --git a/core/src/com/cloud/storage/VolumeVO.java b/core/src/com/cloud/storage/VolumeVO.java index 72b4f237635..20bd92082af 100755 --- a/core/src/com/cloud/storage/VolumeVO.java +++ b/core/src/com/cloud/storage/VolumeVO.java @@ -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; diff --git a/server/src/com/cloud/api/commands/CreateSnapshotCmd.java b/server/src/com/cloud/api/commands/CreateSnapshotCmd.java index 53b3efc9a22..f536c43501d 100644 --- a/server/src/com/cloud/api/commands/CreateSnapshotCmd.java +++ b/server/src/com/cloud/api/commands/CreateSnapshotCmd.java @@ -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; diff --git a/server/src/com/cloud/api/commands/ListVolumesCmd.java b/server/src/com/cloud/api/commands/ListVolumesCmd.java index 2797c2fbf3a..fe5d67730e4 100755 --- a/server/src/com/cloud/api/commands/ListVolumesCmd.java +++ b/server/src/com/cloud/api/commands/ListVolumesCmd.java @@ -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(BaseCmd.Properties.SOURCE_ID.getName(),volume.getSourceId())); volumeData.add(new Pair(BaseCmd.Properties.SOURCE_TYPE.getName(),volume.getSourceType().toString())); - volumeData.add(new Pair(BaseCmd.Properties.HYPERVISOR_TYPE.getName(), getManagementServer().getVolumeHyperType(volume.getId()))); + volumeData.add(new Pair(BaseCmd.Properties.HYPERVISOR.getName(), getManagementServer().getVolumeHyperType(volume.getId()))); vTag[i++] = volumeData; } diff --git a/server/src/com/cloud/async/executor/VolumeOperationExecutor.java b/server/src/com/cloud/async/executor/VolumeOperationExecutor.java index 750bf2f6f9e..14ba25e40f4 100644 --- a/server/src/com/cloud/async/executor/VolumeOperationExecutor.java +++ b/server/src/com/cloud/async/executor/VolumeOperationExecutor.java @@ -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 { diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 1216449b3e9..7682655daba 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -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); } diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index 3de483bf962..61e3ec6cb00 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -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(),0); + VolumeVO created = createVolume(create, vm, template, dc, pod, host.getClusterId(), offering, diskOffering, new ArrayList(),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 avoids, long size) { + ServiceOfferingVO offering, DiskOfferingVO diskOffering, List avoids, long size, HypervisorType hyperType) { StoragePoolVO pool = null; final HashSet avoidPools = new HashSet(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 poolsToAvoid = new ArrayList(); Set podsToAvoid = new HashSet(); Pair 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 diff --git a/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java b/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java index 2cb8f128615..8ed916c51f8 100644 --- a/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java +++ b/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java @@ -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; } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index ac725fdb6c8..f04c9b4023d 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -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 vols = _volsDao.findByInstance(vmId); if( deviceId != null ) { if( deviceId.longValue() > 15 || deviceId.longValue() == 0 || deviceId.longValue() == 3) { diff --git a/ui/scripts/cloud.core.templates.js b/ui/scripts/cloud.core.templates.js index 9a7cf4e4685..bf5706840ff 100644 --- a/ui/scripts/cloud.core.templates.js +++ b/ui/scripts/cloud.core.templates.js @@ -149,8 +149,12 @@ function showTemplatesTab() { var formatSelect = $("#add_template_format").empty(); if (getHypervisorType() == "kvm") { formatSelect.append(""); + formatSelect.append(""); + formatSelect.append(""); } else if (getHypervisorType() == "xenserver") { formatSelect.append(""); + formatSelect.append(""); + formatSelect.append(""); } $("#template_action_new").bind("click", function(event) {