package org.ovirt.engine.api.restapi.resource;
import static java.util.stream.Collectors.toMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.ovirt.engine.api.common.util.DetailHelper;
import org.ovirt.engine.api.model.Bonding;
import org.ovirt.engine.api.model.Host;
import org.ovirt.engine.api.model.HostNic;
import org.ovirt.engine.api.model.HostNicVirtualFunctionsConfiguration;
import org.ovirt.engine.api.model.HostNics;
import org.ovirt.engine.api.model.Link;
import org.ovirt.engine.api.model.Network;
import org.ovirt.engine.api.model.Statistic;
import org.ovirt.engine.api.model.Statistics;
import org.ovirt.engine.api.resource.HostNicResource;
import org.ovirt.engine.api.resource.HostNicsResource;
import org.ovirt.engine.api.restapi.types.Mapper;
import org.ovirt.engine.api.restapi.util.LinkHelper;
import org.ovirt.engine.api.restapi.utils.CustomPropertiesParser;
import org.ovirt.engine.api.utils.ArrayUtils;
import org.ovirt.engine.core.common.businessentities.VDS;
import org.ovirt.engine.core.common.businessentities.network.Bond;
import org.ovirt.engine.core.common.businessentities.network.HostNicVfsConfig;
import org.ovirt.engine.core.common.businessentities.network.NetworkAttachment;
import org.ovirt.engine.core.common.businessentities.network.VdsNetworkInterface;
import org.ovirt.engine.core.common.queries.IdQueryParameters;
import org.ovirt.engine.core.common.queries.VdcQueryReturnValue;
import org.ovirt.engine.core.common.queries.VdcQueryType;
import org.ovirt.engine.core.common.utils.MapNetworkAttachments;
import org.ovirt.engine.core.compat.Guid;
public class BackendHostNicsResource
extends AbstractBackendCollectionResource<HostNic, VdsNetworkInterface>
implements HostNicsResource {
static final String VIRTUAL_FUNCTION_ALLOWED_LABELS = "virtualfunctionallowedlabels";
static final String[] PF_SUB_COLLECTIONS = { VIRTUAL_FUNCTION_ALLOWED_LABELS, "virtualfunctionallowednetworks" };
private static final String UPDATE_VFS_CONFIG_ACTION = "updatevirtualfunctionsconfiguration";
private String hostId;
public BackendHostNicsResource(String hostId) {
super(HostNic.class, VdsNetworkInterface.class);
this.hostId = hostId;
}
public String getHostId() {
return hostId;
}
@Override
public HostNics list() {
HostNics ret = new HostNics();
List<VdsNetworkInterface> ifaces = getCollection();
Map<String, Guid> networkNameToNetworkIdMap = mapNetworkNamesToNetworkIds();
Map<Guid, NetworkAttachment> attachmentsByNetworkId = getAttachmentsByNetworkId();
for (VdsNetworkInterface iface : ifaces) {
HostNic hostNic = populate(map(iface, ifaces), iface);
setCustomProperties(attachmentsByNetworkId, networkNameToNetworkIdMap, hostNic);
String networkName = iface.getNetworkName();
if (networkNameToNetworkIdMap.containsKey(networkName)) {
Guid networkId = networkNameToNetworkIdMap.get(networkName);
hostNic.getNetwork().setId(networkId.toString());
hostNic.getNetwork().setName(null);
}
ret.getHostNics().add(addLinks(hostNic));
}
return addActions(ret);
}
private Map<String, Guid> mapNetworkNamesToNetworkIds() {
List<org.ovirt.engine.core.common.businessentities.network.Network> clusterNetworks = getClusterNetworks();
Map<String, Guid> networkIdByName = new HashMap<>();
for(org.ovirt.engine.core.common.businessentities.network.Network nwk : clusterNetworks) {
networkIdByName.put(nwk.getName(), nwk.getId());
}
return networkIdByName;
}
private void setCustomProperties(Map<Guid, NetworkAttachment> attachmentsByNetworkId,
Map<String, Guid> networkNameToNetworkIdMap,
HostNic hostNic) {
Network network = hostNic.getNetwork();
if (network == null) {
return;
}
String networkName = network.getName();
NetworkAttachment networkAttachment = attachmentsByNetworkId.get(networkNameToNetworkIdMap.get(networkName));
if (networkAttachment == null) {
return;
}
Map<String, String> properties = networkAttachment.getProperties();
if (properties != null) {
hostNic.setProperties(CustomPropertiesParser.fromMap(properties));
}
}
private Map<Guid, NetworkAttachment> getAttachmentsByNetworkId() {
List<NetworkAttachment> attachments = getBackendCollection(NetworkAttachment.class,
VdcQueryType.GetNetworkAttachmentsByHostId,
new IdQueryParameters(asGuid(hostId)));
return new MapNetworkAttachments(attachments).byNetworkId();
}
@Override
protected HostNic addLinks(HostNic hostNic, String... subCollectionsToExclude) {
if (hostNic.isSetVirtualFunctionsConfiguration()) {
return super.addLinks(hostNic, subCollectionsToExclude);
}
else {
final HostNic resultHostNic = super.addLinks(hostNic,
ArrayUtils.concat(PF_SUB_COLLECTIONS, subCollectionsToExclude));
final Iterator<Link> linkIterator = resultHostNic.getActions().getLinks().iterator();
while (linkIterator.hasNext()) {
final Link link = linkIterator.next();
if (link.getRel().equals(UPDATE_VFS_CONFIG_ACTION)) {
linkIterator.remove();
}
}
return resultHostNic;
}
}
@Override
public HostNicResource getNicResource(String id) {
return inject(new BackendHostNicResource(id, this));
}
public Map<Guid, HostNicVfsConfig> findHostNicVfsConfigs() {
final List<HostNicVfsConfig> hostNicVfsConfigs = getBackendCollection(HostNicVfsConfig.class,
VdcQueryType.GetAllVfsConfigByHostId,
new IdQueryParameters(asGuid(hostId)));
return hostNicVfsConfigs.stream().collect(toMap(HostNicVfsConfig::getNicId, x -> x));
}
public Map<Guid, Guid> retriveVfMap() {
final VdcQueryReturnValue returnValue =
runQuery(VdcQueryType.GetVfToPfMapByHostId, new IdQueryParameters(asGuid(hostId)));
return returnValue.getReturnValue();
}
@Override
protected HostNic doPopulate(HostNic model, VdsNetworkInterface entity) {
final HostNic hostNic = super.doPopulate(model, entity);
final Guid nicId = entity.getId();
final HostNicVfsConfig hostNicVfsConfig = findVfsConfig(nicId);
if (hostNicVfsConfig == null) {
final Map<Guid, Guid> vfMap = retriveVfMap();
final Guid physicalFunctionNicId = vfMap.get(nicId);
if (physicalFunctionNicId != null) {
final HostNic physicalFunction = new HostNic();
physicalFunction.setId(physicalFunctionNicId.toString());
hostNic.setPhysicalFunction(physicalFunction);
}
} else {
final Mapper<HostNicVfsConfig, HostNicVirtualFunctionsConfiguration> mapper =
getMapper(HostNicVfsConfig.class,
HostNicVirtualFunctionsConfiguration.class);
final HostNicVirtualFunctionsConfiguration vfsConfigModel =
mapper.map(hostNicVfsConfig, new HostNicVirtualFunctionsConfiguration());
hostNic.setVirtualFunctionsConfiguration(vfsConfigModel);
}
return hostNic;
}
HostNicVfsConfig findVfsConfig(Guid nicId) {
final Map<Guid, HostNicVfsConfig> hostNicVfsConfigs = findHostNicVfsConfigs();
return hostNicVfsConfigs.get(nicId);
}
public HostNic lookupNic(String id, boolean forcePopulate) {
List<VdsNetworkInterface> ifaces = getCollection();
for (VdsNetworkInterface iface : ifaces) {
if (iface.getId().toString().equals(id)) {
HostNic hostNic = map(iface, ifaces);
if (forcePopulate) {
deprecatedPopulate(hostNic, iface);
doPopulate(hostNic, iface);
} else {
populate(hostNic, iface);
}
for (org.ovirt.engine.core.common.businessentities.network.Network nwk : getClusterNetworks()) {
if (nwk.getName().equals(iface.getNetworkName())) {
hostNic.getNetwork().setId(nwk.getId().toString());
hostNic.getNetwork().setName(null);
break;
}
}
return addLinks(hostNic);
}
}
return notFound();
}
/**
* Look for the interface by ID, and raise an error if the interface was not found.
*
* @param id
* The ID of the interface to look for.
* @return The interface.
*/
public VdsNetworkInterface lookupInterface(String id) {
VdsNetworkInterface iface = lookupInterfaceById(id);
return iface == null ? entityNotFound() : iface;
}
private VdsNetworkInterface lookupInterfaceById(String id) {
for (VdsNetworkInterface iface : getCollection()) {
if (iface.getId().toString().equals(id)) {
return iface;
}
}
return null;
}
protected VdsNetworkInterface lookupInterfaceByName(String name) {
for (VdsNetworkInterface iface : getCollection()) {
if (iface.getName().equals(name)) {
return iface;
}
}
return null;
}
protected List<VdsNetworkInterface> getCollection() {
return getBackendCollection(VdcQueryType.GetVdsInterfacesByVdsId, new IdQueryParameters(asGuid(hostId)));
}
protected List<VdsNetworkInterface> getCollection(List<VdsNetworkInterface> collection) {
if (collection != null) {
return collection;
} else {
return getCollection();
}
}
@Override
public HostNic addParents(HostNic hostNic) {
final HostNic nic = super.addParents(hostNic);
final Host host = new Host();
host.setId(hostId);
nic.setHost(host);
if (nic.getPhysicalFunction() != null) {
nic.getPhysicalFunction().setHost(host);
}
return nic;
}
protected HostNic map(VdsNetworkInterface iface, List<VdsNetworkInterface> ifaces) {
return map(iface, null, ifaces);
}
protected HostNic map(VdsNetworkInterface iface, HostNic template, List<VdsNetworkInterface> ifaces) {
HostNic nic = super.map(iface, template);
if (iface.getBonded() != null && iface.getBonded()) {
nic = addSlaveLinks(nic, getCollection(ifaces));
nic = addActiveSlaveLink(nic, iface, getCollection(ifaces));
} else if (iface.getBondName() != null) {
nic = addMasterLink(nic, iface.getBondName(), getCollection(ifaces));
}
return nic;
}
@Override
protected HostNic map(VdsNetworkInterface entity, HostNic template) {
return map(entity, template, null);
}
@Override
protected VdsNetworkInterface map(HostNic entity, VdsNetworkInterface template) {
VdsNetworkInterface iface = super.map(entity, template);
if (entity.isSetNetwork()) {
if (entity.getNetwork().isSetId() || entity.getNetwork().isSetName()) {
org.ovirt.engine.core.common.businessentities.network.Network net = lookupNetwork(entity.getNetwork());
iface.setNetworkName(net.getName());
} else {
iface.setNetworkName(null);
}
}
return iface;
}
protected HostNic addSlaveLinks(HostNic nic, List<VdsNetworkInterface> ifaces) {
if(nic.getBonding() == null) {
nic.setBonding(new Bonding());
}
nic.getBonding().setSlaves(new HostNics());
for (VdsNetworkInterface i : ifaces) {
if (i.isPartOfBond(nic.getName())) {
nic.getBonding().getSlaves().getHostNics().add(slave(i.getId().toString()));
}
}
return nic;
}
protected HostNic slave(String id) {
HostNic slave = new HostNic();
slave.setId(id);
slave.setHost(new Host());
slave.getHost().setId(hostId);
slave = LinkHelper.addLinks(slave, null, false);
slave.setHost(null);
return slave;
}
protected HostNic addActiveSlaveLink(HostNic nic, VdsNetworkInterface iface, List<VdsNetworkInterface> ifaces) {
if (iface instanceof Bond) {
Bond bond = (Bond) iface;
if(nic.getBonding() == null) {
nic.setBonding(new Bonding());
}
for (VdsNetworkInterface i : ifaces) {
if (i.getName().equals(bond.getActiveSlave())) {
nic.getBonding().setActiveSlave(slave(i.getId().toString()));
break;
}
}
}
return nic;
}
protected HostNic addMasterLink(HostNic nic, String bondName, List<VdsNetworkInterface> ifaces) {
for (VdsNetworkInterface i : ifaces) {
if (i.getName().equals(bondName)) {
nic.getLinks().add(masterLink(i.getId().toString()));
break;
}
}
return nic;
}
private Link masterLink(String id) {
Link master = new Link();
master.setRel("master");
master.setHref(idToHref(id));
return master;
}
private String idToHref(String id) {
HostNic master = new HostNic();
master.setId(id);
master.setHost(new Host());
master.getHost().setId(hostId);
return LinkHelper.addLinks(master).getHref();
}
protected org.ovirt.engine.core.common.businessentities.network.Network lookupNetwork(Network network) {
String id = network.getId();
String name = network.getName();
for (org.ovirt.engine.core.common.businessentities.network.Network entity : getBackendCollection(org.ovirt.engine.core.common.businessentities.network.Network.class,
VdcQueryType.GetAllNetworks,
new IdQueryParameters(Guid.Empty))) {
if ((id != null && id.equals(entity.getId().toString())) ||
(name != null && name.equals(entity.getName()))) {
return entity;
}
}
return handleError(new EntityNotFoundException(id != null ? id : name), false);
}
@Override
protected HostNic deprecatedPopulate(HostNic model, VdsNetworkInterface entity) {
Set<String> details = DetailHelper.getDetails(httpHeaders, uriInfo);
if (details.contains("statistics")) {
addStatistics(model, entity);
}
return model;
}
private void addStatistics(HostNic model, VdsNetworkInterface entity) {
model.setStatistics(new Statistics());
HostNicStatisticalQuery query = new HostNicStatisticalQuery(newModel(model.getId()));
List<Statistic> statistics = query.getStatistics(entity);
for (Statistic statistic : statistics) {
LinkHelper.addLinks(statistic, query.getParentType());
}
model.getStatistics().getStatistics().addAll(statistics);
}
@SuppressWarnings("unchecked")
protected List<org.ovirt.engine.core.common.businessentities.network.Network> getClusterNetworks(){
VDS vds = getEntity(VDS.class, VdcQueryType.GetVdsByVdsId, new IdQueryParameters(Guid.createGuidFromStringDefaultEmpty(getHostId())), "Host");
return getEntity(List.class, VdcQueryType.GetAllNetworksByClusterId, new IdQueryParameters(vds.getClusterId()), "Networks");
}
public org.ovirt.engine.core.common.businessentities.network.Network lookupClusterNetwork(Network net) {
List<org.ovirt.engine.core.common.businessentities.network.Network> networks = getClusterNetworks();
if(net.isSetId()){
for(org.ovirt.engine.core.common.businessentities.network.Network nwk : networks){
if (nwk.getId().toString().equals(net.getId())) {
return nwk;
}
}
}else{
String networkName = net.getName();
for(org.ovirt.engine.core.common.businessentities.network.Network nwk : networks){
if(nwk.getName().equals(networkName)) {
return nwk;
}
}
}
return notFound(org.ovirt.engine.core.common.businessentities.network.Network.class);
}
}