2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.manager;
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import com.google.common.util.concurrent.CheckedFuture;
14 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
15 import org.opendaylight.controller.md.sal.binding.api.MountPoint;
16 import org.opendaylight.controller.md.sal.binding.api.MountPointService;
17 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
20 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
21 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.writer.NetconfTransactionCreator;
22 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.writer.NodeWriter;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.RendererName;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.nodes.RendererNode;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.nodes.RendererNodeBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.nodes.RendererNodeKey;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionParameters;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus;
33 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
34 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
35 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
36 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
37 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
38 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
39 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
40 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
44 import java.util.Arrays;
45 import java.util.List;
47 import static org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus.Connected;
48 import static org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus.Connecting;
49 import static org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus.UnableToConnect;
51 public class NodeManager {
53 public static final RendererName iosXeRenderer = new RendererName("ios-xe-renderer");
54 private static final TopologyId TOPOLOGY_ID = new TopologyId("topology-netconf");
55 private static final Logger LOG = LoggerFactory.getLogger(NodeManager.class);
56 private final DataBroker dataBroker;
57 private final MountPointService mountService;
58 private final List<String> requiredCapabilities;
60 public NodeManager(final DataBroker dataBroker, BindingAwareBroker.ProviderContext session) {
61 this.dataBroker = Preconditions.checkNotNull(dataBroker);
62 mountService = Preconditions.checkNotNull(session.getSALService(MountPointService.class));
63 requiredCapabilities = new RequiredCapabilities().initializeRequiredCapabilities();
66 public void syncNodes(Node dataAfter, Node dataBefore) {
68 if (dataBefore == null && dataAfter != null) {
69 createNode(dataAfter);
71 // Connected/disconnected node
72 if (dataBefore != null && dataAfter != null) {
73 updateNode(dataAfter);
76 if (dataBefore != null && dataAfter == null) {
77 removeNode(dataBefore);
81 private void createNode(Node node) {
82 LOG.info("Registering new node {}", node.getNodeId().getValue());
83 NetconfNode netconfNode = getNodeAugmentation(node);
84 if (netconfNode == null) {
87 NetconfNodeConnectionStatus.ConnectionStatus connectionStatus = netconfNode.getConnectionStatus();
88 switch (connectionStatus) {
90 LOG.info("Connecting device {} ...", node.getNodeId().getValue());
94 resolveConnectedNode(node, netconfNode);
95 LOG.info("Node {} is ready, added to available nodes for IOS-XE Renderer", node.getNodeId().getValue());
97 case UnableToConnect: {
98 LOG.info("Unable to connect device {}", node.getNodeId().getValue());
104 private void updateNode(Node node) {
105 NetconfNode netconfNode = getNodeAugmentation(node);
106 if (netconfNode == null || netconfNode.getConnectionStatus() == null) {
109 NetconfNodeConnectionStatus.ConnectionStatus afterNodeStatus = netconfNode.getConnectionStatus();
110 if (afterNodeStatus.equals(Connected)) {
111 resolveConnectedNode(node, netconfNode);
112 LOG.info("Node {} is ready, added to available nodes for IOS-XE Renderer", node.getNodeId().getValue());
114 if (afterNodeStatus.equals(Connecting)) {
115 resolveDisconnectedNode(node);
116 LOG.info("Node {} has been disconnected, removing from available nodes", node.getNodeId().getValue());
118 if (afterNodeStatus.equals(UnableToConnect)) {
119 resolveDisconnectedNode(node);
120 LOG.info("Unable to connect node {}, removing from available nodes", node.getNodeId().getValue());
124 private void removeNode(Node node) {
125 resolveDisconnectedNode(node);
126 LOG.info("Node {} has been removed", node.getNodeId().getValue());
129 private void resolveConnectedNode(Node node, NetconfNode netconfNode) {
130 InstanceIdentifier mountPointIid = getMountpointIid(node);
131 // Mountpoint iid == path in renderer-node
132 RendererNode rendererNode = remapNode(mountPointIid);
133 NodeWriter nodeWriter = new NodeWriter();
134 nodeWriter.cache(rendererNode);
135 if (isCapableNetconfDevice(node, netconfNode)) {
136 resolveDisconnectedNode(node);
139 IpAddress managementIpAddress = netconfNode.getHost().getIpAddress();
140 if (managementIpAddress == null) {
141 LOG.warn("Node {} does not contain management ip address", node.getNodeId().getValue());
142 resolveDisconnectedNode(node);
145 nodeWriter.commitToDatastore(dataBroker);
148 private void resolveDisconnectedNode(Node node) {
149 InstanceIdentifier mountPointIid = getMountpointIid(node);
150 RendererNode rendererNode = remapNode(mountPointIid);
151 NodeWriter nodeWriter = new NodeWriter();
152 nodeWriter.cache(rendererNode);
153 nodeWriter.removeFromDatastore(dataBroker);
156 private RendererNode remapNode(InstanceIdentifier path) {
157 RendererNodeBuilder rendererNodeBuilder = new RendererNodeBuilder();
158 rendererNodeBuilder.setKey(new RendererNodeKey(path))
160 return rendererNodeBuilder.build();
163 private InstanceIdentifier getMountpointIid(Node node) {
164 return InstanceIdentifier.builder(NetworkTopology.class)
165 .child(Topology.class, new TopologyKey(TOPOLOGY_ID))
166 .child(Node.class, new NodeKey(node.getNodeId())).build();
169 private boolean isCapableNetconfDevice(Node node, NetconfNode netconfAugmentation) {
170 if (netconfAugmentation.getAvailableCapabilities() == null ||
171 netconfAugmentation.getAvailableCapabilities().getAvailableCapability() == null ||
172 netconfAugmentation.getAvailableCapabilities().getAvailableCapability().isEmpty()) {
173 LOG.warn("Node {} does not contain any capabilities", node.getNodeId().getValue());
176 if (!capabilityCheck(netconfAugmentation.getAvailableCapabilities().getAvailableCapability())) {
177 LOG.warn("Node {} does not contain all capabilities required by io-xe-renderer",
178 node.getNodeId().getValue());
184 private boolean capabilityCheck(final List<String> capabilities) {
185 for (String requiredCapability : requiredCapabilities) {
186 if (!capabilities.contains(requiredCapability)) {
193 DataBroker getNodeMountPoint(InstanceIdentifier mountPointIid) {
194 if (mountPointIid == null) {
197 Optional<MountPoint> optionalObject = mountService.getMountPoint(mountPointIid);
198 MountPoint mountPoint;
199 if (optionalObject.isPresent()) {
200 mountPoint = optionalObject.get();
201 if (mountPoint != null) {
202 Optional<DataBroker> optionalDataBroker = mountPoint.getService(DataBroker.class);
203 if (optionalDataBroker.isPresent()) {
204 return optionalDataBroker.get();
206 LOG.debug("Cannot obtain data broker from mountpoint {}", mountPoint);
209 LOG.debug("Cannot obtain mountpoint with IID {}", mountPointIid);
215 NodeId getNodeIdByMountpointIid(InstanceIdentifier mountpointIid) {
216 NodeKey identifier = (NodeKey) mountpointIid.firstKeyOf(Node.class);
217 return identifier.getNodeId();
220 String getNodeManagementIpByMountPointIid(InstanceIdentifier<?> mountpointIid) {
221 NodeId nodeId = getNodeIdByMountpointIid(mountpointIid);
222 InstanceIdentifier<Node> nodeIid = InstanceIdentifier.builder(NetworkTopology.class)
223 .child(Topology.class, new TopologyKey(new TopologyId(NodeManager.TOPOLOGY_ID)))
224 .child(Node.class, new NodeKey(nodeId))
226 ReadOnlyTransaction transaction = dataBroker.newReadOnlyTransaction();
227 CheckedFuture<Optional<Node>, ReadFailedException> submitFuture =
228 transaction.read(LogicalDatastoreType.CONFIGURATION, nodeIid);
231 Optional<Node> nodeOptional = submitFuture.checkedGet();
232 if (nodeOptional.isPresent()) {
233 NetconfNode netconfNode = getNodeAugmentation(nodeOptional.get());
234 return java.util.Optional.ofNullable(netconfNode)
235 .map(NetconfNodeConnectionParameters::getHost)
236 .map(Host::getIpAddress)
237 .map(IpAddress::getIpv4Address)
238 .map(Ipv4Address::getValue)
241 } catch (ReadFailedException e) {
242 LOG.warn("Read node failed {}", nodeId, e);
247 private NetconfNode getNodeAugmentation(Node node) {
248 NetconfNode netconfNode = node.getAugmentation(NetconfNode.class);
249 if (netconfNode == null) {
250 LOG.warn("Node {} is not a netconf device", node.getNodeId().getValue());
256 private class RequiredCapabilities {
258 private static final String ned = "(urn:ios?revision=2016-03-08)ned";
259 private static final String tailfCommon = "(http://tail-f.com/yang/common?revision=2015-05-22)tailf-common";
260 private static final String tailfCliExtension = "(http://tail-f.com/yang/common?revision=2015-03-19)tailf-cli-extensions";
261 private static final String tailfMetaExtension = "(http://tail-f.com/yang/common?revision=2013-11-07)tailf-meta-extensions";
262 private static final String ietfYangTypes = "(urn:ietf:params:xml:ns:yang:ietf-yang-types?revision=2013-07-15)ietf-yang-types";
263 private static final String ietfInetTypes = "(urn:ietf:params:xml:ns:yang:ietf-inet-types?revision=2013-07-15)ietf-inet-types";
266 * Initialize all common capabilities required by IOS-XE renderer. Any connected node is examined whether it's
267 * an appropriate device to handle configuration created by this renderer. A device must support all capabilities
270 * @return list of string representations of required capabilities
272 List<String> initializeRequiredCapabilities() {
273 String capabilityEntries[] = {ned, tailfCommon, tailfCliExtension, tailfMetaExtension, ietfYangTypes,
275 return Arrays.asList(capabilityEntries);