dc17c5105de0939e1eb3c0b971343a16984c765f
[netconf.git] / netconf / netconf-topology-impl / src / main / java / org / opendaylight / netconf / topology / impl / NetconfTopologyImpl.java
1 /*
2  * Copyright (c) 2015 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 package org.opendaylight.netconf.topology.impl;
9
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;
50
51 public class NetconfTopologyImpl extends AbstractNetconfTopology
52         implements DataTreeChangeListener<Node>, AutoCloseable {
53
54     private static final Logger LOG = LoggerFactory.getLogger(NetconfTopologyImpl.class);
55
56     private ListenerRegistration<NetconfTopologyImpl> datastoreListenerRegistration = null;
57
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);
66     }
67
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);
77     }
78
79     @Override
80     public void close() {
81         // close all existing connectors, delete whole topology in datastore?
82         for (final NetconfConnectorDTO connectorDTO : activeConnectors.values()) {
83             connectorDTO.close();
84         }
85         activeConnectors.clear();
86
87         if (datastoreListenerRegistration != null) {
88             datastoreListenerRegistration.close();
89             datastoreListenerRegistration = null;
90         }
91     }
92
93     @Override
94     protected RemoteDeviceHandler<NetconfSessionPreferences> createSalFacade(final RemoteDeviceId id) {
95         return new NetconfDeviceSalFacade(id, mountPointService, dataBroker, topologyId);
96     }
97
98     /**
99      * Invoked by blueprint.
100      */
101     public void init() {
102         final WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
103         initTopology(wtx, LogicalDatastoreType.CONFIGURATION);
104         initTopology(wtx, LogicalDatastoreType.OPERATIONAL);
105         wtx.commit().addCallback(new FutureCallback<CommitInfo>() {
106             @Override
107             public void onSuccess(final CommitInfo result) {
108                 LOG.debug("topology initialization successful");
109             }
110
111             @Override
112             public void onFailure(final Throwable throwable) {
113                 LOG.error("Unable to initialize netconf-topology", throwable);
114             }
115         }, MoreExecutors.directExecutor());
116
117         LOG.debug("Registering datastore listener");
118         datastoreListenerRegistration = dataBroker.registerDataTreeChangeListener(DataTreeIdentifier.create(
119             LogicalDatastoreType.CONFIGURATION, createTopologyListPath(topologyId).child(Node.class)), this);
120     }
121
122     @Override
123     public void onDataTreeChanged(final Collection<DataTreeModification<Node>> collection) {
124         for (final DataTreeModification<Node> change : collection) {
125             final DataObjectModification<Node> rootNode = change.getRootNode();
126             final NodeId nodeId;
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());
133                     break;
134                 case WRITE:
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);
140                     }
141                     connectNode(nodeId, rootNode.getDataAfter());
142                     break;
143                 case DELETE:
144                     nodeId = getNodeId(rootNode.getIdentifier());
145                     LOG.debug("Config for node {} deleted", nodeId);
146                     disconnectNode(nodeId);
147                     break;
148                 default:
149                     LOG.debug("Unsupported modification type: {}.", rootNode.getModificationType());
150             }
151         }
152     }
153
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);
162     }
163
164     /**
165      * Determines the Netconf Node Node ID, given the node's instance
166      * identifier.
167      *
168      * @param pathArgument Node's path argument
169      * @return     NodeId for the node
170      */
171     @VisibleForTesting
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();
177             }
178         }
179         throw new IllegalStateException("Unable to create NodeId from: " + pathArgument);
180     }
181
182     @VisibleForTesting
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)));
186     }
187 }