package org.ovirt.engine.core.bll.hostdev; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.inject.Inject; import org.ovirt.engine.core.bll.VmCommand; import org.ovirt.engine.core.bll.context.CommandContext; import org.ovirt.engine.core.common.action.VmHostDevicesParameters; import org.ovirt.engine.core.common.businessentities.HostDevice; import org.ovirt.engine.core.common.businessentities.VMStatus; import org.ovirt.engine.core.common.businessentities.VmDevice; import org.ovirt.engine.core.common.businessentities.VmDeviceGeneralType; import org.ovirt.engine.core.common.businessentities.VmHostDevice; import org.ovirt.engine.core.common.errors.EngineMessage; import org.ovirt.engine.core.dao.HostDeviceDao; import org.ovirt.engine.core.dao.VmDeviceDao; public abstract class AbstractVmHostDevicesCommand<P extends VmHostDevicesParameters> extends VmCommand<P> { @Inject private HostDeviceDao hostDeviceDao; @Inject private VmDeviceDao vmDeviceDao; private List<HostDevice> hostDevices; /** * Contains device names that are explicitly passed in the command parameters */ private Set<String> primaryDeviceNames; public AbstractVmHostDevicesCommand(P parameters, CommandContext cmdContext) { super(parameters, cmdContext); primaryDeviceNames = new HashSet<>(parameters.getDeviceNames()); } @Override protected boolean validate() { if (getParameters().getDeviceNames() == null || getParameters().getDeviceNames().isEmpty()) { failValidation(EngineMessage.ACTION_TYPE_FAILED_DEVICE_MUST_BE_SPECIFIED); } if (getVm() == null) { return failValidation(EngineMessage.ACTION_TYPE_FAILED_VM_NOT_FOUND); } // hot(un)plug not supported (yet) if (getVm().getStatus() != VMStatus.Down) { return failVmStatusIllegal(); } if (getVm().getDedicatedVmForVdsList().isEmpty()) { return failValidation(EngineMessage.ACTION_TYPE_FAILED_VM_NOT_PINNED_TO_HOST); } if (getVm().getDedicatedVmForVdsList().size() > 1) { return failValidation(EngineMessage.ACTION_TYPE_FAILED_VM_PINNED_TO_MULTIPLE_HOSTS); } if (getHostDevices() == null) { return failValidation(EngineMessage.ACTION_TYPE_FAILED_HOST_DEVICE_NOT_FOUND); } return true; } protected Set<String> getPrimaryDeviceNames() { return primaryDeviceNames; } private List<HostDevice> getHostDevices() { if (hostDevices == null) { hostDevices = new ArrayList<>(); for (String deviceName : getParameters().getDeviceNames()) { HostDevice hostDevice = fetchHostDevice(deviceName); if (hostDevice == null) { return null; } hostDevices.add(hostDevice); } } return hostDevices; } protected Set<HostDevice> getAffectedHostDevices() { Set<HostDevice> affectedDevices = new HashSet<>(); for (HostDevice hostDevice : getHostDevices()) { affectedDevices.addAll(getDeviceAtomicGroup(hostDevice)); } return affectedDevices; } private Collection<HostDevice> getDeviceAtomicGroup(HostDevice hostDevice) { if (!hasIommu(hostDevice)) { return Collections.singleton(hostDevice); } // only single dedicated host allowed return hostDeviceDao.getHostDevicesByHostIdAndIommuGroup(getVm().getDedicatedVmForVdsList().get(0), hostDevice.getIommuGroup()); } protected boolean hasIommu(HostDevice hostDevice) { // iommu group restriction only applicable to 'pci' devices return hostDevice.isPci() && hostDevice.getIommuGroup() != null; } private HostDevice fetchHostDevice(String deviceName) { // single dedicated host allowed. return hostDeviceDao.getHostDeviceByHostIdAndDeviceName(getVm().getDedicatedVmForVdsList().get(0), deviceName); } protected Map<String, VmHostDevice> getExistingVmHostDevicesByName() { List<VmDevice> existingDevices = vmDeviceDao.getVmDeviceByVmIdAndType(getVmId(), VmDeviceGeneralType.HOSTDEV); List<VmHostDevice> result = new ArrayList<>(); for (VmDevice device : existingDevices) { result.add(new VmHostDevice(device)); } return getVmDeviceUtils().vmDevicesByDevice(result); } }