Long volumeId = command.getId();
Long deviceId = command.getDeviceId();
Account caller = UserContext.current().getCaller();
// Check that the volume ID is valid
VolumeInfo volume = volFactory.getVolume(volumeId);
// Check that the volume is a data volume
if (volume == null || volume.getVolumeType() != Volume.Type.DATADISK) {
throw new InvalidParameterValueException(
"Please specify a valid data volume.");
}
// Check that the volume is not currently attached to any VM
if (volume.getInstanceId() != null) {
throw new InvalidParameterValueException(
"Please specify a volume that is not attached to any VM.");
}
// Check that the volume is not destroyed
if (volume.getState() == Volume.State.Destroy) {
throw new InvalidParameterValueException(
"Please specify a volume that is not destroyed.");
}
// Check that the virtual machine ID is valid and it's a user vm
UserVmVO vm = _userVmDao.findById(vmId);
if (vm == null || vm.getType() != VirtualMachine.Type.User) {
throw new InvalidParameterValueException(
"Please specify a valid User VM.");
}
// Check that the VM is in the correct state
if (vm.getState() != State.Running && vm.getState() != State.Stopped) {
throw new InvalidParameterValueException(
"Please specify a VM that is either running or stopped.");
}
// Check that the device ID is valid
if (deviceId != null) {
if (deviceId.longValue() == 0) {
throw new InvalidParameterValueException(
"deviceId can't be 0, which is used by Root device");
}
}
// Check that the number of data volumes attached to VM is less than
// that supported by hypervisor
List<VolumeVO> existingDataVolumes = _volsDao.findByInstanceAndType(
vmId, Volume.Type.DATADISK);
int maxDataVolumesSupported = getMaxDataVolumesSupported(vm);
if (existingDataVolumes.size() >= maxDataVolumesSupported) {
throw new InvalidParameterValueException(
"The specified VM already has the maximum number of data disks ("
+ maxDataVolumesSupported
+ "). Please specify another VM.");
}
// Check that the VM and the volume are in the same zone
if (vm.getDataCenterId() != volume.getDataCenterId()) {
throw new InvalidParameterValueException(
"Please specify a VM that is in the same zone as the volume.");
}
// 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");
}
}
// if target VM has associated VM snapshots
List<VMSnapshotVO> vmSnapshots = _vmSnapshotDao.findByVm(vmId);
if(vmSnapshots.size() > 0){
throw new InvalidParameterValueException(
"Unable to attach volume, please specify a VM that does not have VM snapshots");
}
// permission check
_accountMgr.checkAccess(caller, null, true, volume, vm);
if (!(Volume.State.Allocated.equals(volume.getState())
|| Volume.State.Ready.equals(volume.getState()) || Volume.State.Uploaded
.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());
VolumeVO dataDiskVol = _volsDao.findById(volume.getId());
StoragePoolVO dataDiskStoragePool = _storagePoolDao.findById(dataDiskVol.getPoolId());
// managed storage can be used for different types of hypervisors
// only perform this check if the volume's storage pool is not null and not managed
if (dataDiskStoragePool != null && !dataDiskStoragePool.isManaged()) {
if (dataDiskHyperType != HypervisorType.None
&& rootDiskHyperType != dataDiskHyperType) {
throw new InvalidParameterValueException(
"Can't attach a volume created by: " + dataDiskHyperType
+ " to a " + rootDiskHyperType + " vm");
}
}
deviceId = getDeviceId(vmId, deviceId);
VolumeInfo volumeOnPrimaryStorage = volume;
// Check if volume is stored on secondary storage
boolean isVolumeOnSec = false;
VolumeInfo volOnSecondary = volFactory.getVolume(volume.getId(), DataStoreRole.Image);
if (volOnSecondary != null) {
isVolumeOnSec = true;
}
boolean createVolumeOnBackend = true;