d4179abd88da115e5686a9c64ef4483d7d6a73a8
[netconf.git] / apps / 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 edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
12 import io.netty.util.concurrent.EventExecutor;
13 import java.util.Collection;
14 import javax.annotation.PreDestroy;
15 import javax.inject.Inject;
16 import javax.inject.Singleton;
17 import org.opendaylight.aaa.encrypt.AAAEncryptionService;
18 import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
19 import org.opendaylight.controller.config.threadpool.ThreadPool;
20 import org.opendaylight.mdsal.binding.api.DataBroker;
21 import org.opendaylight.mdsal.binding.api.DataObjectModification;
22 import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
23 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
24 import org.opendaylight.mdsal.binding.api.DataTreeModification;
25 import org.opendaylight.mdsal.binding.api.RpcProviderService;
26 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
27 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
28 import org.opendaylight.netconf.client.NetconfClientDispatcher;
29 import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas;
30 import org.opendaylight.netconf.client.mdsal.api.CredentialProvider;
31 import org.opendaylight.netconf.client.mdsal.api.DeviceActionFactory;
32 import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager;
33 import org.opendaylight.netconf.client.mdsal.api.SslHandlerFactoryProvider;
34 import org.opendaylight.netconf.topology.spi.AbstractNetconfTopology;
35 import org.opendaylight.netconf.topology.spi.NetconfConnectorDTO;
36 import org.opendaylight.netconf.topology.spi.NetconfNodeUtils;
37 import org.opendaylight.netconf.topology.spi.NetconfTopologyRPCProvider;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev221225.NetconfNodeTopologyService;
39 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
40 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
41 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
42 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
43 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
44 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
45 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
46 import org.opendaylight.yangtools.concepts.Registration;
47 import org.opendaylight.yangtools.yang.binding.Identifier;
48 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
49 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
50 import org.osgi.service.component.annotations.Activate;
51 import org.osgi.service.component.annotations.Component;
52 import org.osgi.service.component.annotations.Deactivate;
53 import org.osgi.service.component.annotations.Reference;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57 // Non-final for testing
58 @Singleton
59 @Component(service = { })
60 public class NetconfTopologyImpl extends AbstractNetconfTopology
61         implements DataTreeChangeListener<Node>, AutoCloseable {
62     private static final Logger LOG = LoggerFactory.getLogger(NetconfTopologyImpl.class);
63
64     private Registration dtclReg;
65     private Registration rpcReg;
66
67     @Inject
68     @Activate
69     public NetconfTopologyImpl(
70             @Reference(target = "(type=netconf-client-dispatcher)") final NetconfClientDispatcher clientDispatcher,
71             @Reference(target = "(type=global-event-executor)") final EventExecutor eventExecutor,
72             @Reference(target = "(type=global-netconf-ssh-scheduled-executor)")
73             final ScheduledThreadPool keepaliveExecutor,
74             @Reference(target = "(type=global-netconf-processing-executor)") final ThreadPool processingExecutor,
75             @Reference final SchemaResourceManager schemaRepositoryProvider, @Reference final DataBroker dataBroker,
76             @Reference final DOMMountPointService mountPointService,
77             @Reference final AAAEncryptionService encryptionService,
78             @Reference final RpcProviderService rpcProviderService, @Reference final BaseNetconfSchemas baseSchemas,
79             @Reference final CredentialProvider credentialProvider,
80             @Reference final SslHandlerFactoryProvider sslHandlerFactoryProvider,
81             @Reference final DeviceActionFactory deviceActionFactory) {
82         this(NetconfNodeUtils.DEFAULT_TOPOLOGY_NAME, clientDispatcher, eventExecutor, keepaliveExecutor,
83             processingExecutor, schemaRepositoryProvider, dataBroker, mountPointService, encryptionService,
84             rpcProviderService, baseSchemas, credentialProvider, sslHandlerFactoryProvider, deviceActionFactory);
85     }
86
87     public NetconfTopologyImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher,
88             final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
89             final ThreadPool processingExecutor, final SchemaResourceManager schemaRepositoryProvider,
90             final DataBroker dataBroker, final DOMMountPointService mountPointService,
91             final AAAEncryptionService encryptionService, final RpcProviderService rpcProviderService,
92             final BaseNetconfSchemas baseSchemas, final CredentialProvider credentialProvider,
93             final SslHandlerFactoryProvider sslHandlerFactoryProvider) {
94         this(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor, processingExecutor,
95                 schemaRepositoryProvider, dataBroker, mountPointService, encryptionService, rpcProviderService,
96                 baseSchemas, credentialProvider, sslHandlerFactoryProvider, null);
97     }
98
99     @SuppressFBWarnings(value = "MC_OVERRIDABLE_METHOD_CALL_IN_CONSTRUCTOR",
100         justification = "DTCL registration of 'this'")
101     public NetconfTopologyImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher,
102             final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
103             final ThreadPool processingExecutor, final SchemaResourceManager schemaRepositoryProvider,
104             final DataBroker dataBroker, final DOMMountPointService mountPointService,
105             final AAAEncryptionService encryptionService, final RpcProviderService rpcProviderService,
106             final BaseNetconfSchemas baseSchemas, final CredentialProvider credentialProvider,
107             final SslHandlerFactoryProvider sslHandlerFactoryProvider, final DeviceActionFactory deviceActionFactory) {
108         super(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor, processingExecutor,
109                 schemaRepositoryProvider, dataBroker, mountPointService, encryptionService, deviceActionFactory,
110                 baseSchemas, credentialProvider, sslHandlerFactoryProvider);
111
112         LOG.debug("Registering datastore listener");
113         dtclReg = dataBroker.registerDataTreeChangeListener(DataTreeIdentifier.create(
114             LogicalDatastoreType.CONFIGURATION, createTopologyListPath(topologyId).child(Node.class)), this);
115         rpcReg = rpcProviderService.registerRpcImplementation(NetconfNodeTopologyService.class,
116             new NetconfTopologyRPCProvider(dataBroker, encryptionService, topologyId));
117     }
118
119     @PreDestroy
120     @Deactivate
121     @Override
122     public void close() {
123         if (rpcReg != null) {
124             rpcReg.close();
125             rpcReg = null;
126         }
127
128         // close all existing connectors, delete whole topology in datastore?
129         for (final NetconfConnectorDTO connectorDTO : activeConnectors.values()) {
130             connectorDTO.close();
131         }
132         activeConnectors.clear();
133
134         if (dtclReg != null) {
135             dtclReg.close();
136             dtclReg = null;
137         }
138     }
139
140     @Override
141     public void onDataTreeChanged(final Collection<DataTreeModification<Node>> collection) {
142         for (final DataTreeModification<Node> change : collection) {
143             final DataObjectModification<Node> rootNode = change.getRootNode();
144             final NodeId nodeId;
145             switch (rootNode.getModificationType()) {
146                 case SUBTREE_MODIFIED:
147                     nodeId = getNodeId(rootNode.getIdentifier());
148                     LOG.debug("Config for node {} updated", nodeId);
149                     disconnectNode(nodeId);
150                     connectNode(nodeId, rootNode.getDataAfter());
151                     break;
152                 case WRITE:
153                     nodeId = getNodeId(rootNode.getIdentifier());
154                     LOG.debug("Config for node {} created", nodeId);
155                     if (activeConnectors.containsKey(nodeId)) {
156                         LOG.warn("RemoteDevice{{}} was already configured, reconfiguring..", nodeId);
157                         disconnectNode(nodeId);
158                     }
159                     connectNode(nodeId, rootNode.getDataAfter());
160                     break;
161                 case DELETE:
162                     nodeId = getNodeId(rootNode.getIdentifier());
163                     LOG.debug("Config for node {} deleted", nodeId);
164                     disconnectNode(nodeId);
165                     break;
166                 default:
167                     LOG.debug("Unsupported modification type: {}.", rootNode.getModificationType());
168             }
169         }
170     }
171
172     /**
173      * Determines the Netconf Node Node ID, given the node's instance
174      * identifier.
175      *
176      * @param pathArgument Node's path argument
177      * @return     NodeId for the node
178      */
179     @VisibleForTesting
180     static NodeId getNodeId(final InstanceIdentifier.PathArgument pathArgument) {
181         if (pathArgument instanceof InstanceIdentifier.IdentifiableItem<?, ?>) {
182             final Identifier<?> key = ((InstanceIdentifier.IdentifiableItem<?, ?>) pathArgument).getKey();
183             if (key instanceof NodeKey) {
184                 return ((NodeKey) key).getNodeId();
185             }
186         }
187         throw new IllegalStateException("Unable to create NodeId from: " + pathArgument);
188     }
189
190     @VisibleForTesting
191     static KeyedInstanceIdentifier<Topology, TopologyKey> createTopologyListPath(final String topologyId) {
192         final InstanceIdentifier<NetworkTopology> networkTopology = InstanceIdentifier.create(NetworkTopology.class);
193         return networkTopology.child(Topology.class, new TopologyKey(new TopologyId(topologyId)));
194     }
195 }