// 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.