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