23a46aaa5a7a22e1bd710656ae28c2655b03d65a
[netconf.git] / netconf / netconf-topology-singleton / src / main / java / org / opendaylight / netconf / topology / singleton / impl / NetconfTopologyManager.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.netconf.topology.singleton.impl;
10
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;
19 import java.util.Map;
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;
56
57 public class NetconfTopologyManager
58         implements ClusteredDataTreeChangeListener<Node>, NetconfTopologySingletonService, AutoCloseable {
59
60     private static final Logger LOG = LoggerFactory.getLogger(NetconfTopologyManager.class);
61
62     private final Map<InstanceIdentifier<Node>, NetconfTopologyContext> contexts = new HashMap<>();
63     private final Map<InstanceIdentifier<Node>, ClusterSingletonServiceRegistration>
64             clusterRegistrations = new HashMap<>();
65
66     private ListenerRegistration<NetconfTopologyManager> dataChangeListenerRegistration;
67
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;
79
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);
97     }
98
99     // Blueprint init method
100     public void init() {
101         dataChangeListenerRegistration = registerDataTreeChangeListener(topologyId);
102     }
103
104     @Override
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());
114                     break;
115                 case WRITE:
116                     if (contexts.containsKey(dataModifIdent)) {
117                         LOG.debug("RemoteDevice{{}} was already configured, reconfiguring node...", nodeId);
118                         refreshNetconfDeviceContext(dataModifIdent, rootNode.getDataAfter());
119                     } else {
120                         LOG.debug("Config for node {} created", nodeId);
121                         startNetconfDeviceContext(dataModifIdent, rootNode.getDataAfter());
122                     }
123                     break;
124                 case DELETE:
125                     LOG.debug("Config for node {} deleted", nodeId);
126                     stopNetconfDeviceContext(dataModifIdent);
127                     break;
128                 default:
129                     LOG.warn("Unknown operation for {}.", nodeId);
130             }
131         }
132     }
133
134     private void refreshNetconfDeviceContext(final InstanceIdentifier<Node> instanceIdentifier, final Node node) {
135         final NetconfTopologyContext context = contexts.get(instanceIdentifier);
136         context.refresh(createSetup(instanceIdentifier, node));
137     }
138
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());
144
145         final Timeout actorResponseWaitTime = new Timeout(Duration.create(netconfNode.getActorResponseWaitTime(),
146                 "seconds"));
147
148         final ServiceGroupIdentifier serviceGroupIdent =
149                 ServiceGroupIdentifier.create(instanceIdentifier.toString());
150
151         final NetconfTopologyContext newNetconfTopologyContext =
152                 new NetconfTopologyContext(createSetup(instanceIdentifier, node), serviceGroupIdent,
153                         actorResponseWaitTime);
154
155         final ClusterSingletonServiceRegistration clusterSingletonServiceRegistration  =
156                 clusterSingletonServiceProvider.registerClusterSingletonService(newNetconfTopologyContext);
157
158         clusterRegistrations.put(instanceIdentifier, clusterSingletonServiceRegistration);
159         contexts.put(instanceIdentifier, newNetconfTopologyContext);
160     }
161
162     private void stopNetconfDeviceContext(final InstanceIdentifier<Node> instanceIdentifier) {
163         if (contexts.containsKey(instanceIdentifier)) {
164             try {
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);
169             }
170             contexts.remove(instanceIdentifier);
171             clusterRegistrations.remove(instanceIdentifier);
172         }
173     }
174
175     @Override
176     public void close() {
177         if (dataChangeListenerRegistration != null) {
178             dataChangeListenerRegistration.close();
179             dataChangeListenerRegistration = null;
180         }
181         contexts.forEach((instanceIdentifier, netconfTopologyContext) -> {
182             try {
183                 netconfTopologyContext.closeFinal();
184             } catch (final Exception e) {
185                 LOG.error("Error at closing topology context. InstanceIdentifier: " + instanceIdentifier, e);
186             }
187         });
188         clusterRegistrations.forEach((instanceIdentifier, clusterSingletonServiceRegistration) -> {
189             try {
190                 clusterSingletonServiceRegistration.close();
191             } catch (final Exception e) {
192                 LOG.error("Error at unregistering from cluster. InstanceIdentifier: " + instanceIdentifier, e);
193             }
194         });
195         contexts.clear();
196         clusterRegistrations.clear();
197     }
198
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>() {
204             @Override
205             public void onSuccess(final Void result) {
206                 LOG.debug("topology initialization successful");
207             }
208
209             @Override
210             public void onFailure(@Nonnull final Throwable throwable) {
211                 LOG.error("Unable to initialize netconf-topology, {}", throwable);
212             }
213         });
214
215         LOG.debug("Registering datastore listener");
216         return dataBroker.registerDataTreeChangeListener(
217                         new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
218                                 NetconfTopologyUtils.createTopologyListPath(topologyId).child(Node.class)), this);
219     }
220
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);
229     }
230
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)
237                 .setNode(node)
238                 .setBindingAwareBroker(bindingAwareBroker)
239                 .setActorSystem(actorSystem)
240                 .setEventExecutor(eventExecutor)
241                 .setDomBroker(domBroker)
242                 .setKeepaliveExecutor(keepaliveExecutor)
243                 .setProcessingExecutor(processingExecutor)
244                 .setTopologyId(topologyId)
245                 .setNetconfClientDispatcher(clientDispatcher);
246
247         return builder.build();
248     }
249 }