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.spi;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.collect.ImmutableList;
13 import com.google.common.util.concurrent.FutureCallback;
14 import com.google.common.util.concurrent.MoreExecutors;
15 import com.google.common.util.concurrent.SettableFuture;
16 import java.util.concurrent.ExecutionException;
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.opendaylight.mdsal.binding.api.DataBroker;
19 import org.opendaylight.mdsal.binding.api.Transaction;
20 import org.opendaylight.mdsal.binding.api.TransactionChain;
21 import org.opendaylight.mdsal.binding.api.TransactionChainListener;
22 import org.opendaylight.mdsal.binding.api.WriteTransaction;
23 import org.opendaylight.mdsal.common.api.CommitInfo;
24 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
25 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceId;
26 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev221225.ConnectionOper.ConnectionStatus;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev221225.connection.oper.AvailableCapabilitiesBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev221225.connection.oper.ClusteredConnectionStatusBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev221225.connection.oper.UnavailableCapabilitiesBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev221225.connection.oper.available.capabilities.AvailableCapability;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev221225.connection.oper.unavailable.capabilities.UnavailableCapabilityBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev221225.NetconfNode;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev221225.NetconfNodeBuilder;
36 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
37 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
38 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
39 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
40 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
41 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
42 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
43 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
44 import org.opendaylight.yangtools.yang.common.Empty;
45 import org.opendaylight.yangtools.yang.common.Uint16;
46 import org.opendaylight.yangtools.yang.common.Uint32;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
50 public final class NetconfDeviceTopologyAdapter implements TransactionChainListener, AutoCloseable {
51 private static final Logger LOG = LoggerFactory.getLogger(NetconfDeviceTopologyAdapter.class);
53 private final SettableFuture<Empty> closeFuture = SettableFuture.create();
54 private final @NonNull KeyedInstanceIdentifier<Topology, TopologyKey> topologyPath;
55 private final DataBroker dataBroker;
56 private final RemoteDeviceId id;
58 private TransactionChain txChain;
60 public NetconfDeviceTopologyAdapter(final DataBroker dataBroker,
61 final KeyedInstanceIdentifier<Topology, TopologyKey> topologyPath, final RemoteDeviceId id) {
62 this.dataBroker = requireNonNull(dataBroker);
63 this.topologyPath = requireNonNull(topologyPath);
64 this.id = requireNonNull(id);
65 txChain = dataBroker.createMergingTransactionChain(this);
67 final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
68 LOG.trace("{}: Init device state transaction {} putting if absent operational data started.", id,
69 writeTx.getIdentifier());
70 final var nodePath = nodePath();
71 writeTx.put(LogicalDatastoreType.OPERATIONAL, nodePath, new NodeBuilder()
72 .withKey(nodePath.getKey())
73 .addAugmentation(new NetconfNodeBuilder()
74 .setConnectionStatus(ConnectionStatus.Connecting)
76 .setPort(new PortNumber(Uint16.valueOf(id.address().getPort()))).build())
78 LOG.trace("{}: Init device state transaction {} putting operational data ended.", id, writeTx.getIdentifier());
80 commitTransaction(writeTx, "init");
83 private @NonNull KeyedInstanceIdentifier<Node, NodeKey> nodePath() {
84 return topologyPath.child(Node.class, new NodeKey(new NodeId(id.name())));
87 private @NonNull InstanceIdentifier<NetconfNode> netconfNodePath() {
88 return nodePath().augmentation(NetconfNode.class);
91 public void updateDeviceData(final boolean up, final NetconfDeviceCapabilities capabilities,
92 final Uint32 sessionId) {
93 final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
94 LOG.trace("{}: Update device state transaction {} merging operational data started.",
95 id, writeTx.getIdentifier());
97 // FIXME: this needs to be tied together with node's operational existence
98 writeTx.mergeParentStructurePut(LogicalDatastoreType.OPERATIONAL, netconfNodePath(),
99 newNetconfNodeBuilder(up, capabilities, sessionId).build());
100 LOG.trace("{}: Update device state transaction {} merging operational data ended.",
101 id, writeTx.getIdentifier());
103 commitTransaction(writeTx, "update");
106 public void updateClusteredDeviceData(final boolean up, final String masterAddress,
107 final NetconfDeviceCapabilities capabilities, final Uint32 sessionId) {
108 final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
109 LOG.trace("{}: Update device state transaction {} merging operational data started.",
110 id, writeTx.getIdentifier());
111 writeTx.mergeParentStructurePut(LogicalDatastoreType.OPERATIONAL, netconfNodePath(),
112 newNetconfNodeBuilder(up, capabilities, sessionId)
113 .setClusteredConnectionStatus(new ClusteredConnectionStatusBuilder()
114 .setNetconfMasterNode(masterAddress)
117 LOG.trace("{}: Update device state transaction {} merging operational data ended.",
118 id, writeTx.getIdentifier());
120 commitTransaction(writeTx, "update");
124 public void onTransactionChainFailed(final TransactionChain chain, final Transaction transaction,
125 final Throwable cause) {
126 LOG.warn("{}: TransactionChain({}) {} FAILED!", id, chain, transaction.getIdentifier(), cause);
129 txChain = dataBroker.createMergingTransactionChain(this);
130 LOG.info("{}: TransactionChain reset to {}", id, txChain);
131 // FIXME: restart last update
135 public void onTransactionChainSuccessful(final TransactionChain chain) {
136 LOG.trace("{}: TransactionChain({}) SUCCESSFUL", id, chain);
137 closeFuture.set(Empty.value());
140 public void setDeviceAsFailed(final Throwable throwable) {
141 String reason = throwable != null && throwable.getMessage() != null ? throwable.getMessage() : "Unknown reason";
143 final NetconfNode data = new NetconfNodeBuilder()
145 .setPort(new PortNumber(Uint16.valueOf(id.address().getPort())))
146 .setConnectionStatus(ConnectionStatus.UnableToConnect).setConnectedMessage(reason).build();
148 final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
150 "{}: Setting device state as failed {} putting operational data started.",
151 id, writeTx.getIdentifier());
152 writeTx.mergeParentStructurePut(LogicalDatastoreType.OPERATIONAL, netconfNodePath(), data);
154 "{}: Setting device state as failed {} putting operational data ended.",
155 id, writeTx.getIdentifier());
157 commitTransaction(writeTx, "update-failed-device");
160 private NetconfNodeBuilder newNetconfNodeBuilder(final boolean up, final NetconfDeviceCapabilities capabilities,
161 final Uint32 sessionId) {
162 return new NetconfNodeBuilder()
164 .setPort(new PortNumber(Uint16.valueOf(id.address().getPort())))
165 .setConnectionStatus(up ? ConnectionStatus.Connected : ConnectionStatus.Connecting)
166 .setAvailableCapabilities(new AvailableCapabilitiesBuilder()
167 .setAvailableCapability(ImmutableList.<AvailableCapability>builder()
168 .addAll(capabilities.nonModuleBasedCapabilities())
169 .addAll(capabilities.resolvedCapabilities())
172 .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder()
173 .setUnavailableCapability(capabilities.unresolvedCapabilites().entrySet().stream()
174 .map(unresolved -> new UnavailableCapabilityBuilder()
175 // FIXME: better conversion than 'toString' ?
176 .setCapability(unresolved.getKey().toString())
177 .setFailureReason(unresolved.getValue())
181 .setSessionId(sessionId);
184 private void commitTransaction(final WriteTransaction transaction, final String txType) {
185 LOG.trace("{}: Committing Transaction {}:{}", id, txType, transaction.getIdentifier());
187 transaction.commit().addCallback(new FutureCallback<CommitInfo>() {
189 public void onSuccess(final CommitInfo result) {
190 LOG.trace("{}: Transaction({}) {} SUCCESSFUL", id, txType, transaction.getIdentifier());
194 public void onFailure(final Throwable throwable) {
195 LOG.error("{}: Transaction({}) {} FAILED!", id, txType, transaction.getIdentifier(), throwable);
197 }, MoreExecutors.directExecutor());
201 public void close() {
202 final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
203 LOG.trace("{}: Close device state transaction {} removing all data started.", id, writeTx.getIdentifier());
204 writeTx.delete(LogicalDatastoreType.OPERATIONAL, nodePath());
205 LOG.trace("{}: Close device state transaction {} removing all data ended.", id, writeTx.getIdentifier());
206 commitTransaction(writeTx, "close");
212 } catch (InterruptedException | ExecutionException e) {
213 LOG.error("{}: Transaction(close) {} FAILED!", id, writeTx.getIdentifier(), e);
214 throw new IllegalStateException(id + " Transaction(close) not committed correctly", e);