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
9 package org.opendaylight.netconf.sal.connect.netconf.sal;
11 import com.google.common.base.Preconditions;
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.MoreExecutors;
14 import java.util.ArrayList;
15 import java.util.List;
17 import java.util.concurrent.ExecutionException;
18 import java.util.stream.Collectors;
19 import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
20 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.mdsal.common.api.CommitInfo;
23 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
24 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.AvailableCapabilitiesBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.ClusteredConnectionStatusBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.UnavailableCapabilities;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.UnavailableCapabilitiesBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapability;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.unavailable.capabilities.UnavailableCapability.FailureReason;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.unavailable.capabilities.UnavailableCapabilityBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.network.topology.topology.topology.types.TopologyNetconf;
37 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
38 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopologyBuilder;
39 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
40 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
41 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
42 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
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.NodeBuilder;
46 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
47 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
48 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
49 import org.opendaylight.yangtools.yang.common.QName;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
53 public class NetconfDeviceTopologyAdapter implements AutoCloseable {
55 private static final Logger LOG = LoggerFactory.getLogger(NetconfDeviceTopologyAdapter.class);
57 private final RemoteDeviceId id;
58 private BindingTransactionChain txChain;
60 private final InstanceIdentifier<NetworkTopology> networkTopologyPath;
61 private final KeyedInstanceIdentifier<Topology, TopologyKey> topologyListPath;
62 private static final String UNKNOWN_REASON = "Unknown reason";
64 NetconfDeviceTopologyAdapter(final RemoteDeviceId id, final BindingTransactionChain txChain) {
66 this.txChain = Preconditions.checkNotNull(txChain);
68 this.networkTopologyPath = InstanceIdentifier.builder(NetworkTopology.class).build();
69 this.topologyListPath = networkTopologyPath
70 .child(Topology.class, new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName())));
75 private void initDeviceData() {
76 final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
78 createNetworkTopologyIfNotPresent(writeTx);
80 final InstanceIdentifier<Node> path = id.getTopologyBindingPath();
81 final NodeBuilder nodeBuilder = getNodeIdBuilder(id);
82 NetconfNodeBuilder netconfNodeBuilder = new NetconfNodeBuilder();
83 netconfNodeBuilder.setConnectionStatus(ConnectionStatus.Connecting);
84 netconfNodeBuilder.setHost(id.getHost());
85 netconfNodeBuilder.setPort(new PortNumber(id.getAddress().getPort()));
86 nodeBuilder.addAugmentation(NetconfNode.class, netconfNodeBuilder.build());
87 Node node = nodeBuilder.build();
89 LOG.trace("{}: Init device state transaction {} putting if absent operational data started.",
90 id, writeTx.getIdentifier());
91 writeTx.put(LogicalDatastoreType.OPERATIONAL, path, node);
92 LOG.trace("{}: Init device state transaction {} putting operational data ended.", id, writeTx.getIdentifier());
93 LOG.trace("{}: Init device state transaction {} putting if absent config data started.",
94 id, writeTx.getIdentifier());
95 LOG.trace("{}: Init device state transaction {} putting config data ended.", id, writeTx.getIdentifier());
97 commitTransaction(writeTx, "init");
100 public void updateDeviceData(final boolean up, final NetconfDeviceCapabilities capabilities) {
101 final NetconfNode data = buildDataForNetconfNode(up, capabilities);
103 final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
104 LOG.trace("{}: Update device state transaction {} merging operational data started.",
105 id, writeTx.getIdentifier());
106 writeTx.put(LogicalDatastoreType.OPERATIONAL, id.getTopologyBindingPath().augmentation(NetconfNode.class),
108 LOG.trace("{}: Update device state transaction {} merging operational data ended.",
109 id, writeTx.getIdentifier());
111 commitTransaction(writeTx, "update");
114 public void updateClusteredDeviceData(final boolean up, final String masterAddress,
115 final NetconfDeviceCapabilities capabilities) {
116 final NetconfNode data = buildDataForNetconfClusteredNode(up, masterAddress, capabilities);
118 final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
119 LOG.trace("{}: Update device state transaction {} merging operational data started.",
120 id, writeTx.getIdentifier());
121 writeTx.put(LogicalDatastoreType.OPERATIONAL,
122 id.getTopologyBindingPath().augmentation(NetconfNode.class), data, true);
123 LOG.trace("{}: Update device state transaction {} merging operational data ended.",
124 id, writeTx.getIdentifier());
126 commitTransaction(writeTx, "update");
129 public void setDeviceAsFailed(final Throwable throwable) {
130 String reason = throwable != null && throwable.getMessage() != null ? throwable.getMessage() : UNKNOWN_REASON;
132 final NetconfNode data = new NetconfNodeBuilder()
133 .setHost(id.getHost())
134 .setPort(new PortNumber(id.getAddress().getPort()))
135 .setConnectionStatus(ConnectionStatus.UnableToConnect).setConnectedMessage(reason).build();
137 final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
139 "{}: Setting device state as failed {} putting operational data started.",
140 id, writeTx.getIdentifier());
141 writeTx.put(LogicalDatastoreType.OPERATIONAL,
142 id.getTopologyBindingPath().augmentation(NetconfNode.class), data, true);
144 "{}: Setting device state as failed {} putting operational data ended.",
145 id, writeTx.getIdentifier());
147 commitTransaction(writeTx, "update-failed-device");
150 private NetconfNode buildDataForNetconfNode(final boolean up, final NetconfDeviceCapabilities capabilities) {
151 List<AvailableCapability> capabilityList = new ArrayList<>();
152 capabilityList.addAll(capabilities.getNonModuleBasedCapabilities());
153 capabilityList.addAll(capabilities.getResolvedCapabilities());
155 final AvailableCapabilitiesBuilder avCapabalitiesBuilder = new AvailableCapabilitiesBuilder();
156 avCapabalitiesBuilder.setAvailableCapability(capabilityList);
158 final NetconfNodeBuilder netconfNodeBuilder = new NetconfNodeBuilder()
159 .setHost(id.getHost())
160 .setPort(new PortNumber(id.getAddress().getPort()))
161 .setConnectionStatus(up ? ConnectionStatus.Connected : ConnectionStatus.Connecting)
162 .setAvailableCapabilities(avCapabalitiesBuilder.build())
163 .setUnavailableCapabilities(unavailableCapabilities(capabilities.getUnresolvedCapabilites()));
165 return netconfNodeBuilder.build();
168 private NetconfNode buildDataForNetconfClusteredNode(final boolean up, final String masterNodeAddress,
169 final NetconfDeviceCapabilities capabilities) {
170 List<AvailableCapability> capabilityList = new ArrayList<>();
171 capabilityList.addAll(capabilities.getNonModuleBasedCapabilities());
172 capabilityList.addAll(capabilities.getResolvedCapabilities());
173 final AvailableCapabilitiesBuilder avCapabalitiesBuilder = new AvailableCapabilitiesBuilder();
174 avCapabalitiesBuilder.setAvailableCapability(capabilityList);
176 final NetconfNodeBuilder netconfNodeBuilder = new NetconfNodeBuilder()
177 .setHost(id.getHost())
178 .setPort(new PortNumber(id.getAddress().getPort()))
179 .setConnectionStatus(up ? ConnectionStatus.Connected : ConnectionStatus.Connecting)
180 .setAvailableCapabilities(avCapabalitiesBuilder.build())
181 .setUnavailableCapabilities(unavailableCapabilities(capabilities.getUnresolvedCapabilites()))
182 .setClusteredConnectionStatus(
183 new ClusteredConnectionStatusBuilder().setNetconfMasterNode(masterNodeAddress).build());
185 return netconfNodeBuilder.build();
188 private static UnavailableCapabilities unavailableCapabilities(final Map<QName, FailureReason> input) {
189 return new UnavailableCapabilitiesBuilder().setUnavailableCapability(input.entrySet().stream().map(
190 e -> new UnavailableCapabilityBuilder().setCapability(e.getKey().toString()).setFailureReason(
191 e.getValue()).build()).collect(Collectors.toList())).build();
194 public void removeDeviceConfiguration() {
195 final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
198 "{}: Close device state transaction {} removing all data started.",
199 id, writeTx.getIdentifier());
200 writeTx.delete(LogicalDatastoreType.OPERATIONAL, id.getTopologyBindingPath());
202 "{}: Close device state transaction {} removing all data ended.",
203 id, writeTx.getIdentifier());
206 writeTx.commit().get();
207 } catch (InterruptedException | ExecutionException e) {
208 LOG.error("{}: Transaction(close) {} FAILED!", id, writeTx.getIdentifier(), e);
209 throw new IllegalStateException(id + " Transaction(close) not committed correctly", e);
213 private void createNetworkTopologyIfNotPresent(final WriteTransaction writeTx) {
215 final NetworkTopology networkTopology = new NetworkTopologyBuilder().build();
216 LOG.trace("{}: Transaction {} merging {} container to ensure its presence", id, writeTx.getIdentifier(),
217 NetworkTopology.QNAME);
218 writeTx.merge(LogicalDatastoreType.OPERATIONAL, networkTopologyPath, networkTopology);
220 final Topology topology =
221 new TopologyBuilder().setTopologyId(new TopologyId(TopologyNetconf.QNAME.getLocalName())).build();
222 LOG.trace("{}: Transaction {} merging {} container to ensure its presence", id, writeTx.getIdentifier(),
224 writeTx.merge(LogicalDatastoreType.OPERATIONAL, topologyListPath, topology);
227 private void commitTransaction(final WriteTransaction transaction, final String txType) {
228 LOG.trace("{}: Committing Transaction {}:{}", id, txType,
229 transaction.getIdentifier());
231 transaction.commit().addCallback(new FutureCallback<CommitInfo>() {
233 public void onSuccess(final CommitInfo result) {
234 LOG.trace("{}: Transaction({}) {} SUCCESSFUL", id, txType,
235 transaction.getIdentifier());
239 public void onFailure(final Throwable throwable) {
240 LOG.error("{}: Transaction({}) {} FAILED!", id, txType,
241 transaction.getIdentifier(), throwable);
242 throw new IllegalStateException(
243 id + " Transaction(" + txType + ") not committed correctly", throwable);
245 }, MoreExecutors.directExecutor());
248 private static NodeBuilder getNodeIdBuilder(final RemoteDeviceId id) {
249 final NodeBuilder nodeBuilder = new NodeBuilder();
250 nodeBuilder.withKey(new NodeKey(new NodeId(id.getName())));
255 public void close() {
256 removeDeviceConfiguration();
259 public void setTxChain(final BindingTransactionChain txChain) {
260 this.txChain = Preconditions.checkNotNull(txChain);