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.sal.NetconfDeviceSalFacade;
35 import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.BaseNetconfSchemas;
36 import org.opendaylight.netconf.sal.connect.util.NetconfTopologyRPCProvider;
37 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
38 import org.opendaylight.netconf.topology.spi.AbstractNetconfTopology;
39 import org.opendaylight.netconf.topology.spi.NetconfConnectorDTO;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeTopologyService;
41 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
42 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
43 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
44 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
45 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
46 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
47 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
48 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
49 import org.opendaylight.yangtools.concepts.ListenerRegistration;
50 import org.opendaylight.yangtools.concepts.ObjectRegistration;
51 import org.opendaylight.yangtools.yang.binding.Identifier;
52 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
53 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
57 public class NetconfTopologyImpl extends AbstractNetconfTopology
58 implements DataTreeChangeListener<Node>, AutoCloseable {
60 private static final Logger LOG = LoggerFactory.getLogger(NetconfTopologyImpl.class);
62 private final RpcProviderService rpcProviderService;
63 private ListenerRegistration<NetconfTopologyImpl> datastoreListenerRegistration = null;
64 private ObjectRegistration<?> rpcReg = null;
66 public NetconfTopologyImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher,
67 final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
68 final ThreadPool processingExecutor, final SchemaResourceManager schemaRepositoryProvider,
69 final DataBroker dataBroker, final DOMMountPointService mountPointService,
70 final AAAEncryptionService encryptionService, final RpcProviderService rpcProviderService,
71 final BaseNetconfSchemas baseSchemas) {
72 this(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor, processingExecutor,
73 schemaRepositoryProvider, dataBroker, mountPointService, encryptionService, rpcProviderService,
77 public NetconfTopologyImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher,
78 final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
79 final ThreadPool processingExecutor, final SchemaResourceManager schemaRepositoryProvider,
80 final DataBroker dataBroker, final DOMMountPointService mountPointService,
81 final AAAEncryptionService encryptionService, final RpcProviderService rpcProviderService,
82 final BaseNetconfSchemas baseSchemas, final DeviceActionFactory deviceActionFactory) {
83 super(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor, processingExecutor,
84 schemaRepositoryProvider, dataBroker, mountPointService, encryptionService, deviceActionFactory,
86 this.rpcProviderService = requireNonNull(rpcProviderService);
96 // close all existing connectors, delete whole topology in datastore?
97 for (final NetconfConnectorDTO connectorDTO : activeConnectors.values()) {
100 activeConnectors.clear();
102 if (datastoreListenerRegistration != null) {
103 datastoreListenerRegistration.close();
104 datastoreListenerRegistration = null;
109 protected RemoteDeviceHandler createSalFacade(final RemoteDeviceId id) {
110 return new NetconfDeviceSalFacade(id, mountPointService, dataBroker, topologyId);
114 * Invoked by blueprint.
117 final WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
118 initTopology(wtx, LogicalDatastoreType.CONFIGURATION);
119 initTopology(wtx, LogicalDatastoreType.OPERATIONAL);
120 wtx.commit().addCallback(new FutureCallback<CommitInfo>() {
122 public void onSuccess(final CommitInfo result) {
123 LOG.debug("topology initialization successful");
127 public void onFailure(final Throwable throwable) {
128 LOG.error("Unable to initialize netconf-topology", throwable);
130 }, MoreExecutors.directExecutor());
132 LOG.debug("Registering datastore listener");
133 datastoreListenerRegistration = dataBroker.registerDataTreeChangeListener(DataTreeIdentifier.create(
134 LogicalDatastoreType.CONFIGURATION, createTopologyListPath(topologyId).child(Node.class)), this);
135 rpcReg = rpcProviderService.registerRpcImplementation(NetconfNodeTopologyService.class,
136 new NetconfTopologyRPCProvider(dataBroker, encryptionService, topologyId));
140 public void onDataTreeChanged(final Collection<DataTreeModification<Node>> collection) {
141 for (final DataTreeModification<Node> change : collection) {
142 final DataObjectModification<Node> rootNode = change.getRootNode();
144 switch (rootNode.getModificationType()) {
145 case SUBTREE_MODIFIED:
146 nodeId = getNodeId(rootNode.getIdentifier());
147 LOG.debug("Config for node {} updated", nodeId);
148 disconnectNode(nodeId);
149 connectNode(nodeId, rootNode.getDataAfter());
152 nodeId = getNodeId(rootNode.getIdentifier());
153 LOG.debug("Config for node {} created", nodeId);
154 if (activeConnectors.containsKey(nodeId)) {
155 LOG.warn("RemoteDevice{{}} was already configured, reconfiguring..", nodeId);
156 disconnectNode(nodeId);
158 connectNode(nodeId, rootNode.getDataAfter());
161 nodeId = getNodeId(rootNode.getIdentifier());
162 LOG.debug("Config for node {} deleted", nodeId);
163 disconnectNode(nodeId);
166 LOG.debug("Unsupported modification type: {}.", rootNode.getModificationType());
171 private void initTopology(final WriteTransaction wtx, final LogicalDatastoreType datastoreType) {
172 // FIXME: this should be a put(), as we are initializing and will be re-populating the datastore with all the
173 // devices. Whathever has been there before should be nuked to properly re-align lifecycle
174 wtx.merge(datastoreType, InstanceIdentifier.builder(NetworkTopology.class)
175 .child(Topology.class, new TopologyKey(new TopologyId(topologyId)))
176 .build(), new TopologyBuilder().setTopologyId(new TopologyId(topologyId)).build());
180 * Determines the Netconf Node Node ID, given the node's instance
183 * @param pathArgument Node's path argument
184 * @return NodeId for the node
187 static NodeId getNodeId(final InstanceIdentifier.PathArgument pathArgument) {
188 if (pathArgument instanceof InstanceIdentifier.IdentifiableItem<?, ?>) {
189 final Identifier<?> key = ((InstanceIdentifier.IdentifiableItem<?, ?>) pathArgument).getKey();
190 if (key instanceof NodeKey) {
191 return ((NodeKey) key).getNodeId();
194 throw new IllegalStateException("Unable to create NodeId from: " + pathArgument);
198 static KeyedInstanceIdentifier<Topology, TopologyKey> createTopologyListPath(final String topologyId) {
199 final InstanceIdentifier<NetworkTopology> networkTopology = InstanceIdentifier.create(NetworkTopology.class);
200 return networkTopology.child(Topology.class, new TopologyKey(new TopologyId(topologyId)));