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 static java.util.Objects.requireNonNull;
12 import com.google.common.annotations.VisibleForTesting;
13 import com.google.common.util.concurrent.FutureCallback;
14 import com.google.common.util.concurrent.MoreExecutors;
15 import io.netty.util.concurrent.EventExecutor;
16 import java.util.Collection;
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.binding.api.WriteTransaction;
27 import org.opendaylight.mdsal.common.api.CommitInfo;
28 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
29 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
30 import org.opendaylight.netconf.client.NetconfClientDispatcher;
31 import org.opendaylight.netconf.sal.connect.api.DeviceActionFactory;
32 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
33 import org.opendaylight.netconf.sal.connect.api.SchemaResourceManager;
34 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
35 import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceSalFacade;
36 import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.BaseNetconfSchemas;
37 import org.opendaylight.netconf.sal.connect.util.NetconfTopologyRPCProvider;
38 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
39 import org.opendaylight.netconf.topology.spi.AbstractNetconfTopology;
40 import org.opendaylight.netconf.topology.spi.NetconfConnectorDTO;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeTopologyService;
42 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
43 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopologyBuilder;
44 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
45 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
46 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
47 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
48 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
49 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
50 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
51 import org.opendaylight.yangtools.concepts.ListenerRegistration;
52 import org.opendaylight.yangtools.concepts.ObjectRegistration;
53 import org.opendaylight.yangtools.yang.binding.Identifier;
54 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
55 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
59 public class NetconfTopologyImpl extends AbstractNetconfTopology
60 implements DataTreeChangeListener<Node>, AutoCloseable {
62 private static final Logger LOG = LoggerFactory.getLogger(NetconfTopologyImpl.class);
64 private final RpcProviderService rpcProviderService;
65 private ListenerRegistration<NetconfTopologyImpl> datastoreListenerRegistration = null;
66 private ObjectRegistration<?> rpcReg = null;
68 public NetconfTopologyImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher,
69 final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
70 final ThreadPool processingExecutor, final SchemaResourceManager schemaRepositoryProvider,
71 final DataBroker dataBroker, final DOMMountPointService mountPointService,
72 final AAAEncryptionService encryptionService, final RpcProviderService rpcProviderService,
73 final BaseNetconfSchemas baseSchemas) {
74 this(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor, processingExecutor,
75 schemaRepositoryProvider, dataBroker, mountPointService, encryptionService, rpcProviderService,
79 public NetconfTopologyImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher,
80 final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
81 final ThreadPool processingExecutor, final SchemaResourceManager schemaRepositoryProvider,
82 final DataBroker dataBroker, final DOMMountPointService mountPointService,
83 final AAAEncryptionService encryptionService, final RpcProviderService rpcProviderService,
84 final BaseNetconfSchemas baseSchemas, final DeviceActionFactory deviceActionFactory) {
85 super(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor, processingExecutor,
86 schemaRepositoryProvider, dataBroker, mountPointService, encryptionService, deviceActionFactory,
88 this.rpcProviderService = requireNonNull(rpcProviderService);
98 // close all existing connectors, delete whole topology in datastore?
99 for (final NetconfConnectorDTO connectorDTO : activeConnectors.values()) {
100 connectorDTO.close();
102 activeConnectors.clear();
104 if (datastoreListenerRegistration != null) {
105 datastoreListenerRegistration.close();
106 datastoreListenerRegistration = null;
111 protected RemoteDeviceHandler<NetconfSessionPreferences> createSalFacade(final RemoteDeviceId id) {
112 return new NetconfDeviceSalFacade(id, mountPointService, dataBroker, topologyId);
116 * Invoked by blueprint.
119 final WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
120 initTopology(wtx, LogicalDatastoreType.CONFIGURATION);
121 initTopology(wtx, LogicalDatastoreType.OPERATIONAL);
122 wtx.commit().addCallback(new FutureCallback<CommitInfo>() {
124 public void onSuccess(final CommitInfo result) {
125 LOG.debug("topology initialization successful");
129 public void onFailure(final Throwable throwable) {
130 LOG.error("Unable to initialize netconf-topology", throwable);
132 }, MoreExecutors.directExecutor());
134 LOG.debug("Registering datastore listener");
135 datastoreListenerRegistration = dataBroker.registerDataTreeChangeListener(DataTreeIdentifier.create(
136 LogicalDatastoreType.CONFIGURATION, createTopologyListPath(topologyId).child(Node.class)), this);
137 rpcReg = rpcProviderService.registerRpcImplementation(NetconfNodeTopologyService.class,
138 new NetconfTopologyRPCProvider(dataBroker, encryptionService, topologyId));
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());
173 private void initTopology(final WriteTransaction wtx, final LogicalDatastoreType datastoreType) {
174 final NetworkTopology networkTopology = new NetworkTopologyBuilder().build();
175 final InstanceIdentifier<NetworkTopology> networkTopologyId =
176 InstanceIdentifier.builder(NetworkTopology.class).build();
177 wtx.merge(datastoreType, networkTopologyId, networkTopology);
178 final Topology topology = new TopologyBuilder().setTopologyId(new TopologyId(topologyId)).build();
179 wtx.merge(datastoreType,
180 networkTopologyId.child(Topology.class, new TopologyKey(new TopologyId(topologyId))), topology);
184 * Determines the Netconf Node Node ID, given the node's instance
187 * @param pathArgument Node's path argument
188 * @return NodeId for the node
191 static NodeId getNodeId(final InstanceIdentifier.PathArgument pathArgument) {
192 if (pathArgument instanceof InstanceIdentifier.IdentifiableItem<?, ?>) {
193 final Identifier<?> key = ((InstanceIdentifier.IdentifiableItem<?, ?>) pathArgument).getKey();
194 if (key instanceof NodeKey) {
195 return ((NodeKey) key).getNodeId();
198 throw new IllegalStateException("Unable to create NodeId from: " + pathArgument);
202 static KeyedInstanceIdentifier<Topology, TopologyKey> createTopologyListPath(final String topologyId) {
203 final InstanceIdentifier<NetworkTopology> networkTopology = InstanceIdentifier.create(NetworkTopology.class);
204 return networkTopology.child(Topology.class, new TopologyKey(new TopologyId(topologyId)));