/*
* Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.endpoint;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.groupbasedpolicy.api.EpRendererAugmentation;
import org.opendaylight.groupbasedpolicy.api.EpRendererAugmentationRegistry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterL3PrefixEndpointInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Prefix;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContextBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContextInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayL3Context;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayL3ContextBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
import org.opendaylight.yangtools.yang.binding.Augmentation;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.Map;
import java.util.concurrent.ExecutionException;
public class OfOverlayAug implements EpRendererAugmentation, AutoCloseable {
private final static InstanceIdentifier<Nodes> nodesIid = InstanceIdentifier.builder(Nodes.class).build();
private static final Logger LOG = LoggerFactory.getLogger(OfOverlayAug.class);
private final DataBroker dataProvider;
private EpRendererAugmentationRegistry epRendererAugmentationRegistry;
public OfOverlayAug(DataBroker dataProvider, EpRendererAugmentationRegistry epRendererAugmentationRegistry) {
this.dataProvider = dataProvider;
this.epRendererAugmentationRegistry = epRendererAugmentationRegistry;
epRendererAugmentationRegistry.register(this);
}
@Override
public Map.Entry<Class<? extends Augmentation<Endpoint>>, Augmentation<Endpoint>> buildEndpointAugmentation(
RegisterEndpointInput input) {
// In order to support both the port-name and the data-path information, allow
// an EP to register without the augmentations, and resolve later.
OfOverlayContextBuilder ictx = checkAugmentation(input);
if (ictx != null) {
return new SimpleImmutableEntry<Class<? extends Augmentation<Endpoint>>, Augmentation<Endpoint>>(
OfOverlayContext.class, ictx.build());
}
return null;
}
@Override
public Map.Entry<Class<? extends Augmentation<EndpointL3>>, Augmentation<EndpointL3>> buildEndpointL3Augmentation(
RegisterEndpointInput input) {
OfOverlayContextBuilder ictx = checkAugmentation(input);
if (ictx != null) {
return new SimpleImmutableEntry<Class<? extends Augmentation<EndpointL3>>, Augmentation<EndpointL3>>(
OfOverlayL3Context.class, new OfOverlayL3ContextBuilder(ictx.build()).build());
}
return null;
}
@Override
public Map.Entry<Class<? extends Augmentation<EndpointL3Prefix>>, Augmentation<EndpointL3Prefix>> buildL3PrefixEndpointAugmentation(
RegisterL3PrefixEndpointInput input) {
return null;
}
private OfOverlayContextBuilder checkAugmentation(RegisterEndpointInput input) {
OfOverlayContextInput ictx = input.getAugmentation(OfOverlayContextInput.class);
if (ictx == null) {
return null;
}
OfOverlayContextBuilder ictxBuilder = new OfOverlayContextBuilder(ictx);
if (ictx.getPortName() != null && ictx.getNodeId() != null && ictx.getNodeConnectorId() != null) {
return ictxBuilder;
}
/*
* In the case where they've provided just the port name, go see if
* we can find the NodeId and NodeConnectorId from inventory.
*/
if (ictx.getPortName() != null) {
NodeInfo augmentation = fetchAugmentation(ictx.getPortName().getValue());
if (augmentation != null) {
ictxBuilder.setNodeId(augmentation.getNode().getId());
ictxBuilder.setNodeConnectorId(augmentation.getNodeConnector().getId());
}
}
return ictxBuilder;
}
private NodeInfo fetchAugmentation(String portName) {
NodeInfo nodeInfo = null;
if (dataProvider != null) {
Optional<Nodes> result;
try {
result = dataProvider.newReadOnlyTransaction().read(LogicalDatastoreType.OPERATIONAL, nodesIid).get();
if (result.isPresent()) {
Nodes nodes = result.get();
for (Node node : nodes.getNode()) {
if (node.getNodeConnector() != null) {
boolean found = false;
for (NodeConnector nc : node.getNodeConnector()) {
FlowCapableNodeConnector fcnc = nc.getAugmentation(FlowCapableNodeConnector.class);
if (fcnc.getName().equals(portName)) {
nodeInfo = new NodeInfo(nc, node);
found = true;
break;
}
}
if (found)
break;
}
}
}
} catch (InterruptedException | ExecutionException e) {
LOG.error("Caught exception in fetchAugmentation portName", e);
}
}
return nodeInfo;
}
@Override
public void close() throws Exception {
epRendererAugmentationRegistry.unregister(this);
}
/**
* A immutable wrapper class around node, nodeConnector info so we can pass a final
* object inside OnSuccess anonymous inner class
*/
private static class NodeInfo {
private NodeConnector nodeConnector;
private Node node;
protected NodeInfo(NodeConnector nc, Node node) {
Preconditions.checkNotNull(nc, "Node connector cannot be null");
Preconditions.checkNotNull(node, "Node cannot be null");
this.nodeConnector = nc;
this.node = node;
}
protected Node getNode() {
return this.node;
}
protected NodeConnector getNodeConnector() {
return this.nodeConnector;
}
}
}