/*
* Copyright (c) 2016 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.vpp.util;
import static org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus.Connected;
import static org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus.Connecting;
import javax.annotation.Nonnull;
import java.util.Collection;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.SettableFuture;
import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class GbpVppNetconfConnectionProbe implements ClusteredDataTreeChangeListener<Node> {
private static final Logger LOG = LoggerFactory.getLogger(GbpVppNetconfConnectionProbe.class);
private final ListenerRegistration<GbpVppNetconfConnectionProbe> registeredListener;
private final DataTreeIdentifier<Node> path;
private SettableFuture<Boolean> futureStatus;
@SuppressWarnings("FieldCanBeLocal")
private final String TOPOLOGY_ID = "topology-netconf";
GbpVppNetconfConnectionProbe(final NodeKey nodekey, final SettableFuture<Boolean> futureStatus, final DataBroker dataBroker) {
this.futureStatus = Preconditions.checkNotNull(futureStatus);
Preconditions.checkArgument(!futureStatus.isDone());
Preconditions.checkNotNull(nodekey);
Preconditions.checkNotNull(dataBroker);
final InstanceIdentifier<Node> nodeIid = InstanceIdentifier.builder(NetworkTopology.class)
.child(Topology.class, new TopologyKey(new TopologyId(TOPOLOGY_ID)))
.child(Node.class, nodekey)
.build();
path = new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL, nodeIid);
LOG.debug("Registering listener for node {}", nodekey);
registeredListener = dataBroker.registerDataTreeChangeListener(path, this);
}
@Override
public void onDataTreeChanged(@Nonnull Collection<DataTreeModification<Node>> changes) {
changes.forEach(modification -> {
final DataObjectModification<Node> rootNode = modification.getRootNode();
final Node node = rootNode.getDataAfter();
if (node == null) {
futureStatus.set(false);
unregister();
return;
}
final NetconfNode netconfNode = getNodeAugmentation(node);
final NodeId nodeId = node.getNodeId();
if (netconfNode == null || netconfNode.getConnectionStatus() == null) {
LOG.warn("Node {} does not contain netconf augmentation", nodeId);
futureStatus.set(false);
unregister();
} else {
final NetconfNodeConnectionStatus.ConnectionStatus status = netconfNode.getConnectionStatus();
if (status.equals(Connecting)) {
LOG.debug("Node {} is connecting", nodeId);
} else if (status.equals(Connected)) {
LOG.debug("Node {} connected", nodeId);
futureStatus.set(true);
unregister();
} else { // Unable to connect
LOG.warn("Unable to connect node {}", nodeId);
futureStatus.set(false);
unregister();
}
}
});
}
private NetconfNode getNodeAugmentation(Node node) {
NetconfNode netconfNode = node.getAugmentation(NetconfNode.class);
if (netconfNode == null) {
LOG.warn("Node {} is not a netconf device", node.getNodeId().getValue());
return null;
}
return netconfNode;
}
void unregister() {
LOG.debug("Listener for path {} unregistered", path.getRootIdentifier());
if (registeredListener != null) {
registeredListener.close();
}
}
@VisibleForTesting
SettableFuture<Boolean> getFutureStatus() {
return futureStatus;
}
}