// If local storage is disabled then attaching a volume with local disk
// offering not allowed
DataCenterVO dataCenter = _dcDao.findById(volume.getDataCenterId());
if (!dataCenter.isLocalStorageEnabled()) {
DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume
.getDiskOfferingId());
if (diskOffering.getUseLocalStorage()) {
throw new InvalidParameterValueException(
"Zone is not configured to use local storage but volume's disk offering "
+ diskOffering.getName() + " uses it");
}
}
// permission check
_accountMgr.checkAccess(caller, null, true, volume, vm);
// Check if volume is stored on secondary Storage.
boolean isVolumeOnSec = false;
VolumeHostVO volHostVO = _volumeHostDao.findByVolumeId(volume.getId());
if (volHostVO != null) {
isVolumeOnSec = true;
if (!(volHostVO.getDownloadState() == Status.DOWNLOADED)) {
throw new InvalidParameterValueException(
"Volume is not uploaded yet. Please try this operation once the volume is uploaded");
}
}
if (!(Volume.State.Allocated.equals(volume.getState())
|| Volume.State.Ready.equals(volume.getState()) || Volume.State.UploadOp
.equals(volume.getState()))) {
throw new InvalidParameterValueException(
"Volume state must be in Allocated, Ready or in Uploaded state");
}
VolumeVO rootVolumeOfVm = null;
List<VolumeVO> rootVolumesOfVm = _volsDao.findByInstanceAndType(vmId,
Volume.Type.ROOT);
if (rootVolumesOfVm.size() != 1) {
throw new CloudRuntimeException(
"The VM "
+ vm.getHostName()
+ " has more than one ROOT volume and is in an invalid state.");
} else {
rootVolumeOfVm = rootVolumesOfVm.get(0);
}
HypervisorType rootDiskHyperType = vm.getHypervisorType();
HypervisorType dataDiskHyperType = _volsDao.getHypervisorType(volume
.getId());
if (dataDiskHyperType != HypervisorType.None
&& rootDiskHyperType != dataDiskHyperType) {
throw new InvalidParameterValueException(
"Can't attach a volume created by: " + dataDiskHyperType
+ " to a " + rootDiskHyperType + " vm");
}
// allocate deviceId
List<VolumeVO> vols = _volsDao.findByInstance(vmId);
if (deviceId != null) {
if (deviceId.longValue() > 15 || deviceId.longValue() == 0
|| deviceId.longValue() == 3) {
throw new RuntimeException("deviceId should be 1,2,4-15");
}
for (VolumeVO vol : vols) {
if (vol.getDeviceId().equals(deviceId)) {
throw new RuntimeException("deviceId " + deviceId
+ " is used by VM " + vm.getHostName());
}
}
} else {
// allocate deviceId here
List<String> devIds = new ArrayList<String>();
for (int i = 1; i < 15; i++) {
devIds.add(String.valueOf(i));
}
devIds.remove("3");
for (VolumeVO vol : vols) {
devIds.remove(vol.getDeviceId().toString().trim());
}
deviceId = Long.parseLong(devIds.iterator().next());
}
boolean createVolumeOnBackend = true;
if (rootVolumeOfVm.getState() == Volume.State.Allocated) {
createVolumeOnBackend = false;
if (isVolumeOnSec) {
throw new CloudRuntimeException(
"Cant attach uploaded volume to the vm which is not created. Please start it and then retry");
}
}
// create volume on the backend only when vm's root volume is allocated
if (createVolumeOnBackend) {
if (volume.getState().equals(Volume.State.Allocated)
|| isVolumeOnSec) {
/* Need to create the volume */
VMTemplateVO rootDiskTmplt = _templateDao.findById(vm
.getTemplateId());
DataCenterVO dcVO = _dcDao.findById(vm
.getDataCenterId());
HostPodVO pod = _podDao.findById(vm.getPodIdToDeployIn());
StoragePoolVO rootDiskPool = _storagePoolDao
.findById(rootVolumeOfVm.getPoolId());
ServiceOfferingVO svo = _serviceOfferingDao.findById(vm
.getServiceOfferingId());
DiskOfferingVO diskVO = _diskOfferingDao.findById(volume
.getDiskOfferingId());
Long clusterId = (rootDiskPool == null ? null : rootDiskPool
.getClusterId());
if (!isVolumeOnSec) {
volume = _storageMgr.createVolume(volume, vm,
rootDiskTmplt, dcVO, pod, clusterId, svo, diskVO,
new ArrayList<StoragePoolVO>(), volume.getSize(),
rootDiskHyperType);
} else {
try {
// Format of data disk should be the same as root disk
if (!volHostVO
.getFormat()
.getFileExtension()
.equals(_storageMgr
.getSupportedImageFormatForCluster(rootDiskPool
.getClusterId()))) {
throw new InvalidParameterValueException(
"Failed to attach volume to VM since volumes format "
+ volHostVO.getFormat()
.getFileExtension()
+ " is not compatible with the vm hypervisor type");
}
// Check that there is some shared storage.
StoragePoolVO vmRootVolumePool = _storagePoolDao
.findById(rootVolumeOfVm.getPoolId());
List<StoragePoolVO> sharedVMPools = _storagePoolDao
.findPoolsByTags(
vmRootVolumePool.getDataCenterId(),
vmRootVolumePool.getPodId(),
vmRootVolumePool.getClusterId(), null,
true);
if (sharedVMPools.size() == 0) {
throw new CloudRuntimeException(
"Cannot attach volume since there are no shared storage pools in the VM's cluster to copy the uploaded volume to.");
}
volume = _storageMgr.copyVolumeFromSecToPrimary(volume,
vm, rootDiskTmplt, dcVO, pod,
rootDiskPool.getClusterId(), svo, diskVO,
new ArrayList<StoragePoolVO>(),
volume.getSize(), rootDiskHyperType);
} catch (NoTransitionException e) {
throw new CloudRuntimeException(
"Unable to transition the volume ", e);
}
}
if (volume == null) {
throw new CloudRuntimeException(
"Failed to create volume when attaching it to VM: "
+ vm.getHostName());
}
}
StoragePoolVO vmRootVolumePool = _storagePoolDao
.findById(rootVolumeOfVm.getPoolId());
DiskOfferingVO volumeDiskOffering = _diskOfferingDao
.findById(volume.getDiskOfferingId());
String[] volumeTags = volumeDiskOffering.getTagsArray();
boolean isVolumeOnSharedPool = !volumeDiskOffering
.getUseLocalStorage();
StoragePoolVO sourcePool = _storagePoolDao.findById(volume
.getPoolId());
List<StoragePoolVO> matchingVMPools = _storagePoolDao
.findPoolsByTags(vmRootVolumePool.getDataCenterId(),
vmRootVolumePool.getPodId(),
vmRootVolumePool.getClusterId(), volumeTags,
isVolumeOnSharedPool);
boolean moveVolumeNeeded = true;
if (matchingVMPools.size() == 0) {
String poolType;
if (vmRootVolumePool.getClusterId() != null) {
poolType = "cluster";
} else if (vmRootVolumePool.getPodId() != null) {
poolType = "pod";
} else {
poolType = "zone";
}
throw new CloudRuntimeException(
"There are no storage pools in the VM's " + poolType
+ " with all of the volume's tags ("
+ volumeDiskOffering.getTags() + ").");
} else {
long sourcePoolId = sourcePool.getId();
Long sourcePoolDcId = sourcePool.getDataCenterId();
Long sourcePoolPodId = sourcePool.getPodId();
Long sourcePoolClusterId = sourcePool.getClusterId();