Specialize RemoteDeviceHandler to NetconfSessionPreferences
[netconf.git] / netconf / 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 static java.util.Objects.requireNonNull;
11
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.NetworkTopologyBuilder;
43 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
44 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
45 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
46 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
47 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
48 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
49 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
50 import org.opendaylight.yangtools.concepts.ListenerRegistration;
51 import org.opendaylight.yangtools.concepts.ObjectRegistration;
52 import org.opendaylight.yangtools.yang.binding.Identifier;
53 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
54 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58 public class NetconfTopologyImpl extends AbstractNetconfTopology
59         implements DataTreeChangeListener<Node>, AutoCloseable {
60
61     private static final Logger LOG = LoggerFactory.getLogger(NetconfTopologyImpl.class);
62
63     private final RpcProviderService rpcProviderService;
64     private ListenerRegistration<NetconfTopologyImpl> datastoreListenerRegistration = null;
65     private ObjectRegistration<?> rpcReg = null;
66
67     public NetconfTopologyImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher,
68             final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
69             final ThreadPool processingExecutor, final SchemaResourceManager schemaRepositoryProvider,
70             final DataBroker dataBroker, final DOMMountPointService mountPointService,
71             final AAAEncryptionService encryptionService, final RpcProviderService rpcProviderService,
72             final BaseNetconfSchemas baseSchemas) {
73         this(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor, processingExecutor,
74                 schemaRepositoryProvider, dataBroker, mountPointService, encryptionService, rpcProviderService,
75                 baseSchemas, null);
76     }
77
78     public NetconfTopologyImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher,
79             final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
80             final ThreadPool processingExecutor, final SchemaResourceManager schemaRepositoryProvider,
81             final DataBroker dataBroker, final DOMMountPointService mountPointService,
82             final AAAEncryptionService encryptionService, final RpcProviderService rpcProviderService,
83             final BaseNetconfSchemas baseSchemas, final DeviceActionFactory deviceActionFactory) {
84         super(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor, processingExecutor,
85                 schemaRepositoryProvider, dataBroker, mountPointService, encryptionService, deviceActionFactory,
86                 baseSchemas);
87         this.rpcProviderService = requireNonNull(rpcProviderService);
88     }
89
90     @Override
91     public void close() {
92         if (rpcReg != null) {
93             rpcReg.close();
94             rpcReg = null;
95         }
96
97         // close all existing connectors, delete whole topology in datastore?
98         for (final NetconfConnectorDTO connectorDTO : activeConnectors.values()) {
99             connectorDTO.close();
100         }
101         activeConnectors.clear();
102
103         if (datastoreListenerRegistration != null) {
104             datastoreListenerRegistration.close();
105             datastoreListenerRegistration = null;
106         }
107     }
108
109     @Override
110     protected RemoteDeviceHandler createSalFacade(final RemoteDeviceId id) {
111         return new NetconfDeviceSalFacade(id, mountPointService, dataBroker, topologyId);
112     }
113
114     /**
115      * Invoked by blueprint.
116      */
117     public void init() {
118         final WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
119         initTopology(wtx, LogicalDatastoreType.CONFIGURATION);
120         initTopology(wtx, LogicalDatastoreType.OPERATIONAL);
121         wtx.commit().addCallback(new FutureCallback<CommitInfo>() {
122             @Override
123             public void onSuccess(final CommitInfo result) {
124                 LOG.debug("topology initialization successful");
125             }
126
127             @Override
128             public void onFailure(final Throwable throwable) {
129                 LOG.error("Unable to initialize netconf-topology", throwable);
130             }
131         }, MoreExecutors.directExecutor());
132
133         LOG.debug("Registering datastore listener");
134         datastoreListenerRegistration = dataBroker.registerDataTreeChangeListener(DataTreeIdentifier.create(
135             LogicalDatastoreType.CONFIGURATION, createTopologyListPath(topologyId).child(Node.class)), this);
136         rpcReg = rpcProviderService.registerRpcImplementation(NetconfNodeTopologyService.class,
137             new NetconfTopologyRPCProvider(dataBroker, encryptionService, topologyId));
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     private void initTopology(final WriteTransaction wtx, final LogicalDatastoreType datastoreType) {
173         final NetworkTopology networkTopology = new NetworkTopologyBuilder().build();
174         final InstanceIdentifier<NetworkTopology> networkTopologyId =
175                 InstanceIdentifier.builder(NetworkTopology.class).build();
176         wtx.merge(datastoreType, networkTopologyId, networkTopology);
177         final Topology topology = new TopologyBuilder().setTopologyId(new TopologyId(topologyId)).build();
178         wtx.merge(datastoreType,
179                 networkTopologyId.child(Topology.class, new TopologyKey(new TopologyId(topologyId))), topology);
180     }
181
182     /**
183      * Determines the Netconf Node Node ID, given the node's instance
184      * identifier.
185      *
186      * @param pathArgument Node's path argument
187      * @return     NodeId for the node
188      */
189     @VisibleForTesting
190     static NodeId getNodeId(final InstanceIdentifier.PathArgument pathArgument) {
191         if (pathArgument instanceof InstanceIdentifier.IdentifiableItem<?, ?>) {
192             final Identifier<?> key = ((InstanceIdentifier.IdentifiableItem<?, ?>) pathArgument).getKey();
193             if (key instanceof NodeKey) {
194                 return ((NodeKey) key).getNodeId();
195             }
196         }
197         throw new IllegalStateException("Unable to create NodeId from: " + pathArgument);
198     }
199
200     @VisibleForTesting
201     static KeyedInstanceIdentifier<Topology, TopologyKey> createTopologyListPath(final String topologyId) {
202         final InstanceIdentifier<NetworkTopology> networkTopology = InstanceIdentifier.create(NetworkTopology.class);
203         return networkTopology.child(Topology.class, new TopologyKey(new TopologyId(topologyId)));
204     }
205 }