2 * Copyright (c) 2015 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
8 package org.opendaylight.netconf.topology.impl;
10 import com.google.common.annotations.VisibleForTesting;
11 import com.google.common.util.concurrent.FutureCallback;
12 import com.google.common.util.concurrent.MoreExecutors;
13 import io.netty.util.concurrent.EventExecutor;
14 import java.util.Collection;
15 import org.opendaylight.aaa.encrypt.AAAEncryptionService;
16 import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
17 import org.opendaylight.controller.config.threadpool.ThreadPool;
18 import org.opendaylight.mdsal.binding.api.DataBroker;
19 import org.opendaylight.mdsal.binding.api.DataObjectModification;
20 import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
21 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
22 import org.opendaylight.mdsal.binding.api.DataTreeModification;
23 import org.opendaylight.mdsal.binding.api.WriteTransaction;
24 import org.opendaylight.mdsal.common.api.CommitInfo;
25 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
26 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
27 import org.opendaylight.netconf.client.NetconfClientDispatcher;
28 import org.opendaylight.netconf.sal.connect.api.DeviceActionFactory;
29 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
30 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
31 import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceSalFacade;
32 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
33 import org.opendaylight.netconf.topology.api.SchemaRepositoryProvider;
34 import org.opendaylight.netconf.topology.spi.AbstractNetconfTopology;
35 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
36 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopologyBuilder;
37 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
38 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
39 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
40 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
41 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
42 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
43 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
44 import org.opendaylight.yangtools.concepts.ListenerRegistration;
45 import org.opendaylight.yangtools.yang.binding.Identifier;
46 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
47 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
51 public class NetconfTopologyImpl extends AbstractNetconfTopology
52 implements DataTreeChangeListener<Node>, AutoCloseable {
54 private static final Logger LOG = LoggerFactory.getLogger(NetconfTopologyImpl.class);
56 private ListenerRegistration<NetconfTopologyImpl> datastoreListenerRegistration = null;
58 public NetconfTopologyImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher,
59 final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
60 final ThreadPool processingExecutor,
61 final SchemaRepositoryProvider schemaRepositoryProvider,
62 final DataBroker dataBroker, final DOMMountPointService mountPointService,
63 final AAAEncryptionService encryptionService) {
64 this(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor, processingExecutor,
65 schemaRepositoryProvider, dataBroker, mountPointService, encryptionService, null);
68 public NetconfTopologyImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher,
69 final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
70 final ThreadPool processingExecutor,
71 final SchemaRepositoryProvider schemaRepositoryProvider,
72 final DataBroker dataBroker, final DOMMountPointService mountPointService,
73 final AAAEncryptionService encryptionService,
74 final DeviceActionFactory deviceActionFactory) {
75 super(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor, processingExecutor,
76 schemaRepositoryProvider, dataBroker, mountPointService, encryptionService, deviceActionFactory);
81 // close all existing connectors, delete whole topology in datastore?
82 for (final NetconfConnectorDTO connectorDTO : activeConnectors.values()) {
85 activeConnectors.clear();
87 if (datastoreListenerRegistration != null) {
88 datastoreListenerRegistration.close();
89 datastoreListenerRegistration = null;
94 protected RemoteDeviceHandler<NetconfSessionPreferences> createSalFacade(final RemoteDeviceId id) {
95 return new NetconfDeviceSalFacade(id, mountPointService, dataBroker, topologyId);
99 * Invoked by blueprint.
102 final WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
103 initTopology(wtx, LogicalDatastoreType.CONFIGURATION);
104 initTopology(wtx, LogicalDatastoreType.OPERATIONAL);
105 wtx.commit().addCallback(new FutureCallback<CommitInfo>() {
107 public void onSuccess(final CommitInfo result) {
108 LOG.debug("topology initialization successful");
112 public void onFailure(final Throwable throwable) {
113 LOG.error("Unable to initialize netconf-topology", throwable);
115 }, MoreExecutors.directExecutor());
117 LOG.debug("Registering datastore listener");
118 datastoreListenerRegistration = dataBroker.registerDataTreeChangeListener(DataTreeIdentifier.create(
119 LogicalDatastoreType.CONFIGURATION, createTopologyListPath(topologyId).child(Node.class)), this);
123 public void onDataTreeChanged(final Collection<DataTreeModification<Node>> collection) {
124 for (final DataTreeModification<Node> change : collection) {
125 final DataObjectModification<Node> rootNode = change.getRootNode();
127 switch (rootNode.getModificationType()) {
128 case SUBTREE_MODIFIED:
129 nodeId = getNodeId(rootNode.getIdentifier());
130 LOG.debug("Config for node {} updated", nodeId);
131 disconnectNode(nodeId);
132 connectNode(nodeId, rootNode.getDataAfter());
135 nodeId = getNodeId(rootNode.getIdentifier());
136 LOG.debug("Config for node {} created", nodeId);
137 if (activeConnectors.containsKey(nodeId)) {
138 LOG.warn("RemoteDevice{{}} was already configured, reconfiguring..", nodeId);
139 disconnectNode(nodeId);
141 connectNode(nodeId, rootNode.getDataAfter());
144 nodeId = getNodeId(rootNode.getIdentifier());
145 LOG.debug("Config for node {} deleted", nodeId);
146 disconnectNode(nodeId);
149 LOG.debug("Unsupported modification type: {}.", rootNode.getModificationType());
154 private void initTopology(final WriteTransaction wtx, final LogicalDatastoreType datastoreType) {
155 final NetworkTopology networkTopology = new NetworkTopologyBuilder().build();
156 final InstanceIdentifier<NetworkTopology> networkTopologyId =
157 InstanceIdentifier.builder(NetworkTopology.class).build();
158 wtx.merge(datastoreType, networkTopologyId, networkTopology);
159 final Topology topology = new TopologyBuilder().setTopologyId(new TopologyId(topologyId)).build();
160 wtx.merge(datastoreType,
161 networkTopologyId.child(Topology.class, new TopologyKey(new TopologyId(topologyId))), topology);
165 * Determines the Netconf Node Node ID, given the node's instance
168 * @param pathArgument Node's path argument
169 * @return NodeId for the node
172 static NodeId getNodeId(final InstanceIdentifier.PathArgument pathArgument) {
173 if (pathArgument instanceof InstanceIdentifier.IdentifiableItem<?, ?>) {
174 final Identifier key = ((InstanceIdentifier.IdentifiableItem) pathArgument).getKey();
175 if (key instanceof NodeKey) {
176 return ((NodeKey) key).getNodeId();
179 throw new IllegalStateException("Unable to create NodeId from: " + pathArgument);
183 static KeyedInstanceIdentifier<Topology, TopologyKey> createTopologyListPath(final String topologyId) {
184 final InstanceIdentifier<NetworkTopology> networkTopology = InstanceIdentifier.create(NetworkTopology.class);
185 return networkTopology.child(Topology.class, new TopologyKey(new TopologyId(topologyId)));