Prepare netconf to support YANG 1.1 actions
[netconf.git] / netconf / netconf-topology / 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
9 package org.opendaylight.netconf.topology.impl;
10
11 import com.google.common.util.concurrent.FutureCallback;
12 import com.google.common.util.concurrent.MoreExecutors;
13 import io.netty.util.concurrent.EventExecutor;
14 import java.util.Collection;
15 import javax.annotation.Nonnull;
16 import org.opendaylight.aaa.encrypt.AAAEncryptionService;
17 import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
18 import org.opendaylight.controller.config.threadpool.ThreadPool;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
21 import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
22 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
23 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
24 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
25 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
26 import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
27 import org.opendaylight.mdsal.common.api.CommitInfo;
28 import org.opendaylight.netconf.client.NetconfClientDispatcher;
29 import org.opendaylight.netconf.sal.connect.api.DeviceActionFactory;
30 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
31 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
32 import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceSalFacade;
33 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
34 import org.opendaylight.netconf.topology.AbstractNetconfTopology;
35 import org.opendaylight.netconf.topology.api.SchemaRepositoryProvider;
36 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
37 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopologyBuilder;
38 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
39 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
40 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
41 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
42 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
43 import org.opendaylight.yangtools.concepts.ListenerRegistration;
44 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47
48 public class NetconfTopologyImpl extends AbstractNetconfTopology
49         implements DataTreeChangeListener<Node>, AutoCloseable {
50
51     private static final Logger LOG = LoggerFactory.getLogger(NetconfTopologyImpl.class);
52
53     private ListenerRegistration<NetconfTopologyImpl> datastoreListenerRegistration = null;
54
55     public NetconfTopologyImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher,
56             final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
57             final ThreadPool processingExecutor,
58             final SchemaRepositoryProvider schemaRepositoryProvider,
59             final DataBroker dataBroker, final DOMMountPointService mountPointService,
60             final AAAEncryptionService encryptionService) {
61         this(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor, processingExecutor,
62                 schemaRepositoryProvider, dataBroker, mountPointService, encryptionService, null);
63     }
64
65     public NetconfTopologyImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher,
66             final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
67             final ThreadPool processingExecutor,
68             final SchemaRepositoryProvider schemaRepositoryProvider,
69             final DataBroker dataBroker, final DOMMountPointService mountPointService,
70             final AAAEncryptionService encryptionService,
71             final DeviceActionFactory deviceActionFactory) {
72         super(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor, processingExecutor,
73                 schemaRepositoryProvider, dataBroker, mountPointService, encryptionService, deviceActionFactory);
74     }
75
76     @Override
77     public void close() {
78         // close all existing connectors, delete whole topology in datastore?
79         for (final NetconfConnectorDTO connectorDTO : activeConnectors.values()) {
80             connectorDTO.close();
81         }
82         activeConnectors.clear();
83
84         if (datastoreListenerRegistration != null) {
85             datastoreListenerRegistration.close();
86             datastoreListenerRegistration = null;
87         }
88     }
89
90     @Override
91     protected RemoteDeviceHandler<NetconfSessionPreferences> createSalFacade(final RemoteDeviceId id) {
92         return new NetconfDeviceSalFacade(id, mountPointService, dataBroker);
93     }
94
95     /**
96      * Invoked by blueprint.
97      */
98     public void init() {
99         final WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
100         initTopology(wtx, LogicalDatastoreType.CONFIGURATION);
101         initTopology(wtx, LogicalDatastoreType.OPERATIONAL);
102         wtx.commit().addCallback(new FutureCallback<CommitInfo>() {
103             @Override
104             public void onSuccess(final CommitInfo result) {
105                 LOG.debug("topology initialization successful");
106             }
107
108             @Override
109             public void onFailure(final Throwable throwable) {
110                 LOG.error("Unable to initialize netconf-topology, {}", throwable);
111             }
112         }, MoreExecutors.directExecutor());
113
114         LOG.debug("Registering datastore listener");
115         datastoreListenerRegistration =
116                 dataBroker.registerDataTreeChangeListener(
117                         new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
118                                 TopologyUtil.createTopologyListPath(topologyId).child(Node.class)), this);
119     }
120
121     @Override
122     public void onDataTreeChanged(@Nonnull final Collection<DataTreeModification<Node>> collection) {
123         for (final DataTreeModification<Node> change : collection) {
124             final DataObjectModification<Node> rootNode = change.getRootNode();
125             switch (rootNode.getModificationType()) {
126                 case SUBTREE_MODIFIED:
127                     LOG.debug("Config for node {} updated", TopologyUtil.getNodeId(rootNode.getIdentifier()));
128                     disconnectNode(TopologyUtil.getNodeId(rootNode.getIdentifier()));
129                     connectNode(TopologyUtil.getNodeId(rootNode.getIdentifier()), rootNode.getDataAfter());
130                     break;
131                 case WRITE:
132                     LOG.debug("Config for node {} created", TopologyUtil.getNodeId(rootNode.getIdentifier()));
133                     if (activeConnectors.containsKey(TopologyUtil.getNodeId(rootNode.getIdentifier()))) {
134                         LOG.warn("RemoteDevice{{}} was already configured, reconfiguring..",
135                                 TopologyUtil.getNodeId(rootNode.getIdentifier()));
136                         disconnectNode(TopologyUtil.getNodeId(rootNode.getIdentifier()));
137                     }
138                     connectNode(TopologyUtil.getNodeId(rootNode.getIdentifier()), rootNode.getDataAfter());
139                     break;
140                 case DELETE:
141                     LOG.debug("Config for node {} deleted", TopologyUtil.getNodeId(rootNode.getIdentifier()));
142                     disconnectNode(TopologyUtil.getNodeId(rootNode.getIdentifier()));
143                     break;
144                 default:
145                     LOG.debug("Unsupported modification type: {}.", rootNode.getModificationType());
146             }
147         }
148     }
149
150     private void initTopology(final WriteTransaction wtx, final LogicalDatastoreType datastoreType) {
151         final NetworkTopology networkTopology = new NetworkTopologyBuilder().build();
152         final InstanceIdentifier<NetworkTopology> networkTopologyId =
153                 InstanceIdentifier.builder(NetworkTopology.class).build();
154         wtx.merge(datastoreType, networkTopologyId, networkTopology);
155         final Topology topology = new TopologyBuilder().setTopologyId(new TopologyId(topologyId)).build();
156         wtx.merge(datastoreType,
157                 networkTopologyId.child(Topology.class, new TopologyKey(new TopologyId(topologyId))), topology);
158     }
159
160 }