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.netconf.topology.singleton.impl;
11 import akka.actor.ActorSystem;
12 import akka.util.Timeout;
13 import com.google.common.base.Preconditions;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.Futures;
16 import io.netty.util.concurrent.EventExecutor;
17 import java.util.Collection;
18 import java.util.HashMap;
20 import javax.annotation.Nonnull;
21 import org.opendaylight.controller.cluster.ActorSystemProvider;
22 import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
23 import org.opendaylight.controller.config.threadpool.ThreadPool;
24 import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
25 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
26 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
27 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
28 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
29 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
30 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
31 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
32 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
33 import org.opendaylight.controller.sal.core.api.Broker;
34 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
35 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
36 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
37 import org.opendaylight.netconf.client.NetconfClientDispatcher;
38 import org.opendaylight.netconf.topology.singleton.api.NetconfTopologySingletonService;
39 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
40 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup.NetconfTopologySetupBuilder;
41 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
43 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
44 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopologyBuilder;
45 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
46 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
47 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
48 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
49 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
50 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
51 import org.opendaylight.yangtools.concepts.ListenerRegistration;
52 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55 import scala.concurrent.duration.Duration;
57 public class NetconfTopologyManager
58 implements ClusteredDataTreeChangeListener<Node>, NetconfTopologySingletonService, AutoCloseable {
60 private static final Logger LOG = LoggerFactory.getLogger(NetconfTopologyManager.class);
62 private final Map<InstanceIdentifier<Node>, NetconfTopologyContext> contexts = new HashMap<>();
63 private final Map<InstanceIdentifier<Node>, ClusterSingletonServiceRegistration>
64 clusterRegistrations = new HashMap<>();
66 private ListenerRegistration<NetconfTopologyManager> dataChangeListenerRegistration;
68 private final DataBroker dataBroker;
69 private final RpcProviderRegistry rpcProviderRegistry;
70 private final ClusterSingletonServiceProvider clusterSingletonServiceProvider;
71 private final BindingAwareBroker bindingAwareBroker;
72 private final ScheduledThreadPool keepaliveExecutor;
73 private final ThreadPool processingExecutor;
74 private final Broker domBroker;
75 private final ActorSystem actorSystem;
76 private final EventExecutor eventExecutor;
77 private final NetconfClientDispatcher clientDispatcher;
78 private final String topologyId;
80 public NetconfTopologyManager(final DataBroker dataBroker, final RpcProviderRegistry rpcProviderRegistry,
81 final ClusterSingletonServiceProvider clusterSingletonServiceProvider,
82 final BindingAwareBroker bindingAwareBroker,
83 final ScheduledThreadPool keepaliveExecutor, final ThreadPool processingExecutor,
84 final Broker domBroker, final ActorSystemProvider actorSystemProvider, final EventExecutor eventExecutor,
85 final NetconfClientDispatcher clientDispatcher, final String topologyId) {
86 this.dataBroker = Preconditions.checkNotNull(dataBroker);
87 this.rpcProviderRegistry = Preconditions.checkNotNull(rpcProviderRegistry);
88 this.clusterSingletonServiceProvider = Preconditions.checkNotNull(clusterSingletonServiceProvider);
89 this.bindingAwareBroker = Preconditions.checkNotNull(bindingAwareBroker);
90 this.keepaliveExecutor = Preconditions.checkNotNull(keepaliveExecutor);
91 this.processingExecutor = Preconditions.checkNotNull(processingExecutor);
92 this.domBroker = Preconditions.checkNotNull(domBroker);
93 this.actorSystem = Preconditions.checkNotNull(actorSystemProvider).getActorSystem();
94 this.eventExecutor = Preconditions.checkNotNull(eventExecutor);
95 this.clientDispatcher = Preconditions.checkNotNull(clientDispatcher);
96 this.topologyId = Preconditions.checkNotNull(topologyId);
99 // Blueprint init method
101 dataChangeListenerRegistration = registerDataTreeChangeListener(topologyId);
105 public void onDataTreeChanged(@Nonnull final Collection<DataTreeModification<Node>> changes) {
106 for (final DataTreeModification<Node> change : changes) {
107 final DataObjectModification<Node> rootNode = change.getRootNode();
108 final InstanceIdentifier<Node> dataModifIdent = change.getRootPath().getRootIdentifier();
109 final NodeId nodeId = NetconfTopologyUtils.getNodeId(rootNode.getIdentifier());
110 switch (rootNode.getModificationType()) {
111 case SUBTREE_MODIFIED:
112 LOG.debug("Config for node {} updated", nodeId);
113 refreshNetconfDeviceContext(dataModifIdent, rootNode.getDataAfter());
116 if (contexts.containsKey(dataModifIdent)) {
117 LOG.debug("RemoteDevice{{}} was already configured, reconfiguring node...", nodeId);
118 refreshNetconfDeviceContext(dataModifIdent, rootNode.getDataAfter());
120 LOG.debug("Config for node {} created", nodeId);
121 startNetconfDeviceContext(dataModifIdent, rootNode.getDataAfter());
125 LOG.debug("Config for node {} deleted", nodeId);
126 stopNetconfDeviceContext(dataModifIdent);
129 LOG.warn("Unknown operation for {}.", nodeId);
134 private void refreshNetconfDeviceContext(final InstanceIdentifier<Node> instanceIdentifier, final Node node) {
135 final NetconfTopologyContext context = contexts.get(instanceIdentifier);
136 context.refresh(createSetup(instanceIdentifier, node));
139 private void startNetconfDeviceContext(final InstanceIdentifier<Node> instanceIdentifier, final Node node) {
140 final NetconfNode netconfNode = node.getAugmentation(NetconfNode.class);
141 Preconditions.checkNotNull(netconfNode);
142 Preconditions.checkNotNull(netconfNode.getHost());
143 Preconditions.checkNotNull(netconfNode.getHost().getIpAddress());
145 final Timeout actorResponseWaitTime = new Timeout(Duration.create(netconfNode.getActorResponseWaitTime(),
148 final ServiceGroupIdentifier serviceGroupIdent =
149 ServiceGroupIdentifier.create(instanceIdentifier.toString());
151 final NetconfTopologyContext newNetconfTopologyContext =
152 new NetconfTopologyContext(createSetup(instanceIdentifier, node), serviceGroupIdent,
153 actorResponseWaitTime);
155 final ClusterSingletonServiceRegistration clusterSingletonServiceRegistration =
156 clusterSingletonServiceProvider.registerClusterSingletonService(newNetconfTopologyContext);
158 clusterRegistrations.put(instanceIdentifier, clusterSingletonServiceRegistration);
159 contexts.put(instanceIdentifier, newNetconfTopologyContext);
162 private void stopNetconfDeviceContext(final InstanceIdentifier<Node> instanceIdentifier) {
163 if (contexts.containsKey(instanceIdentifier)) {
165 clusterRegistrations.get(instanceIdentifier).close();
166 contexts.get(instanceIdentifier).closeFinal();
167 } catch (final Exception e) {
168 LOG.warn("Error at closing topology context. InstanceIdentifier: " + instanceIdentifier);
170 contexts.remove(instanceIdentifier);
171 clusterRegistrations.remove(instanceIdentifier);
176 public void close() {
177 if (dataChangeListenerRegistration != null) {
178 dataChangeListenerRegistration.close();
179 dataChangeListenerRegistration = null;
181 contexts.forEach((instanceIdentifier, netconfTopologyContext) -> {
183 netconfTopologyContext.closeFinal();
184 } catch (final Exception e) {
185 LOG.error("Error at closing topology context. InstanceIdentifier: " + instanceIdentifier, e);
188 clusterRegistrations.forEach((instanceIdentifier, clusterSingletonServiceRegistration) -> {
190 clusterSingletonServiceRegistration.close();
191 } catch (final Exception e) {
192 LOG.error("Error at unregistering from cluster. InstanceIdentifier: " + instanceIdentifier, e);
196 clusterRegistrations.clear();
199 private ListenerRegistration<NetconfTopologyManager> registerDataTreeChangeListener(final String topologyId) {
200 final WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
201 initTopology(wtx, LogicalDatastoreType.CONFIGURATION, topologyId);
202 initTopology(wtx, LogicalDatastoreType.OPERATIONAL, topologyId);
203 Futures.addCallback(wtx.submit(), new FutureCallback<Void>() {
205 public void onSuccess(final Void result) {
206 LOG.debug("topology initialization successful");
210 public void onFailure(@Nonnull final Throwable throwable) {
211 LOG.error("Unable to initialize netconf-topology, {}", throwable);
215 LOG.debug("Registering datastore listener");
216 return dataBroker.registerDataTreeChangeListener(
217 new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
218 NetconfTopologyUtils.createTopologyListPath(topologyId).child(Node.class)), this);
221 private void initTopology(final WriteTransaction wtx, final LogicalDatastoreType datastoreType, final String topologyId) {
222 final NetworkTopology networkTopology = new NetworkTopologyBuilder().build();
223 final InstanceIdentifier<NetworkTopology> networkTopologyId =
224 InstanceIdentifier.builder(NetworkTopology.class).build();
225 wtx.merge(datastoreType, networkTopologyId, networkTopology);
226 final Topology topology = new TopologyBuilder().setTopologyId(new TopologyId(topologyId)).build();
227 wtx.merge(datastoreType, networkTopologyId.child(Topology.class,
228 new TopologyKey(new TopologyId(topologyId))), topology);
231 private NetconfTopologySetup createSetup(final InstanceIdentifier<Node> instanceIdentifier, final Node node) {
232 final NetconfTopologySetupBuilder builder = NetconfTopologySetupBuilder.create()
233 .setClusterSingletonServiceProvider(clusterSingletonServiceProvider)
234 .setDataBroker(dataBroker)
235 .setInstanceIdentifier(instanceIdentifier)
236 .setRpcProviderRegistry(rpcProviderRegistry)
238 .setBindingAwareBroker(bindingAwareBroker)
239 .setActorSystem(actorSystem)
240 .setEventExecutor(eventExecutor)
241 .setDomBroker(domBroker)
242 .setKeepaliveExecutor(keepaliveExecutor)
243 .setProcessingExecutor(processingExecutor)
244 .setTopologyId(topologyId)
245 .setNetconfClientDispatcher(clientDispatcher);
247 return builder.build();