2 * Copyright (c) 2015 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
8 package org.opendaylight.netconf.topology.impl;
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;
58 // Non-final for testing
60 @Component(service = { })
61 public class NetconfTopologyImpl extends AbstractNetconfTopology
62 implements DataTreeChangeListener<Node>, AutoCloseable {
63 private static final Logger LOG = LoggerFactory.getLogger(NetconfTopologyImpl.class);
65 private Registration dtclReg;
66 private Registration rpcReg;
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);
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);
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);
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));
123 public void close() {
124 if (rpcReg != null) {
129 // close all existing connectors, delete whole topology in datastore?
130 for (final NetconfConnectorDTO connectorDTO : activeConnectors.values()) {
131 connectorDTO.close();
133 activeConnectors.clear();
135 if (dtclReg != null) {
142 public void onDataTreeChanged(final Collection<DataTreeModification<Node>> collection) {
143 for (final DataTreeModification<Node> change : collection) {
144 final DataObjectModification<Node> rootNode = change.getRootNode();
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());
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);
160 connectNode(nodeId, rootNode.getDataAfter());
163 nodeId = getNodeId(rootNode.getIdentifier());
164 LOG.debug("Config for node {} deleted", nodeId);
165 disconnectNode(nodeId);
168 LOG.debug("Unsupported modification type: {}.", rootNode.getModificationType());
174 * Determines the Netconf Node Node ID, given the node's instance
177 * @param pathArgument Node's path argument
178 * @return NodeId for the node
181 static NodeId getNodeId(final PathArgument pathArgument) {
182 if (pathArgument instanceof IdentifiableItem<?, ?> ident && ident.getKey() instanceof NodeKey nodeKey) {
183 return nodeKey.getNodeId();
185 throw new IllegalStateException("Unable to create NodeId from: " + pathArgument);
189 static KeyedInstanceIdentifier<Topology, TopologyKey> createTopologyListPath(final String topologyId) {
190 return InstanceIdentifier.create(NetworkTopology.class)
191 .child(Topology.class, new TopologyKey(new TopologyId(topologyId)));