2 * Copyright (c) 2016 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.groupbasedpolicy.renderer.vpp.util;
13 import java.util.concurrent.ExecutionException;
15 import javax.annotation.Nonnull;
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
19 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
22 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
23 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.AbstractConfigCommand;
24 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.AbstractInterfaceCommand;
25 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.RoutingCommand;
26 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.interfaces.ConfigCommand;
27 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.lisp.AbstractLispCommand;
28 import org.opendaylight.vbd.impl.transaction.VbdNetconfTransaction;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocol;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocolKey;
32 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
33 import org.opendaylight.yangtools.yang.binding.DataObject;
34 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
38 import com.google.common.base.Optional;
39 import com.google.common.base.Preconditions;
40 import com.google.common.util.concurrent.CheckedFuture;
42 public class GbpNetconfTransaction {
44 public static final byte RETRY_COUNT = 3;
45 private static final Logger LOG = LoggerFactory.getLogger(GbpNetconfTransaction.class);
48 * Netconf wrapper for write and delete operation on a Netconf Device
49 * @param vppIid destination node
50 * @param iid path for Data to be written to
51 * @param data data to be written
52 * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails
53 * @param <T> data type
54 * @return true if transaction is successful, false otherwise
56 public static <T extends DataObject> boolean netconfSyncedWrite(@Nonnull final InstanceIdentifier<Node> vppIid,
57 @Nonnull final InstanceIdentifier<T> iid, @Nonnull final T data, byte retryCounter) {
58 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock();
59 boolean result = write(VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getKey(), iid, data, retryCounter);
60 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock();
64 public static <T extends DataObject> boolean netconfSyncedWrite(@Nonnull final InstanceIdentifier<Node> vppIid,
65 @Nonnull final Map<InstanceIdentifier<T>,T> data, byte retryCounter) {
66 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock();
67 boolean result = write(VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getKey(), data, retryCounter);
68 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock();
73 * Netconf wrapper for merge operation on a Netconf Device
74 * @param vppIid destination node
75 * @param iid path for Data to be merged to
76 * @param data data to be merged
77 * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails
78 * @param <T> data type
79 * @return true if transaction is successful, false otherwise
81 public static <T extends DataObject> boolean netconfSyncedMerge(@Nonnull final InstanceIdentifier<Node> vppIid,
82 @Nonnull final InstanceIdentifier<T> iid, @Nonnull final T data, byte retryCounter) {
83 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock();
84 boolean result = merge(VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getKey(), iid, data, retryCounter);
85 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock();
90 * Netconf wrapper method for synced requests for write operation on a Netconf Device
91 * @param vppIid destination node
92 * @param command config command that needs to be executed
93 * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails
94 * @return true if transaction is successful, false otherwise
96 public static boolean netconfSyncedWrite(@Nonnull final InstanceIdentifier<Node> vppIid, @Nonnull final ConfigCommand command,
98 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock();
99 boolean result = write(VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getKey(), command, retryCounter);
100 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock();
105 * Netconf wrapper method for synced requests for write operation on a Netconf Device
106 * @param vppIid destination node
107 * @param command routing command that needs to be executed
108 * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails
109 * @return true if transaction is successful, false otherwise
111 public static boolean netconfSyncedWrite(@Nonnull final InstanceIdentifier<Node> vppIid, @Nonnull final RoutingCommand command,
113 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock();
114 boolean result = write(VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getKey(), command, retryCounter);
115 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock();
120 * Netconf wrapper method for synced requests for delete operation on a Netconf Device
121 * @param vppIid destination node
122 * @param iid path for Data to be written to
123 * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails
124 * @param <T> data type
125 * @return true if transaction is successful, false otherwise
127 public static <T extends DataObject> boolean netconfSyncedDelete(@Nonnull final InstanceIdentifier<Node> vppIid,
128 @Nonnull final InstanceIdentifier<T> iid, byte retryCounter) {
129 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock();
130 boolean result = deleteIfExists(vppIid, iid, retryCounter);
131 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock();
135 public static <T extends DataObject> boolean netconfSyncedDelete(@Nonnull final InstanceIdentifier<Node> vppIid,
136 @Nonnull Set<InstanceIdentifier<T>> iids , byte retryCounter) {
137 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock();
138 boolean result = deleteIfExists(vppIid, iids, retryCounter);
139 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock();
144 * Netconf wrapper method for synced requests for delete operation on a Netconf Device
145 * @param vppIid destination node
146 * @param command config command that needs to be executed
147 * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails
148 * @return true if transaction is successful, false otherwise
150 public static boolean netconfSyncedDelete(@Nonnull final InstanceIdentifier<Node> vppIid,
151 @Nonnull final ConfigCommand command, byte retryCounter) {
152 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock();
153 boolean result = deleteIfExists(vppIid, command.getIid(), retryCounter);
154 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock();
159 * Netconf wrapper method for synced requests for delete operation on a Netconf Device
160 * @param vppIid destination node
161 * @param command routing command that needs to be executed
162 * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails
163 * @return true if transaction is successful, false otherwise
165 public static boolean netconfSyncedDelete(@Nonnull final InstanceIdentifier<Node> vppIid,
166 @Nonnull final RoutingCommand command, byte retryCounter) {
167 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock();
168 boolean result = deleteIfExists(vppIid, command.getIid(), retryCounter);
169 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock();
174 * Use {@link ConfigCommand} to put data into netconf transaction and submit. Transaction is restarted if failed
176 * @param mountpoint to access remote device
177 * @param command config command with data, datastore type and iid
178 * @param retryCounter number of attempts
179 * @return true if transaction is successful, false otherwise
181 private static boolean write(final DataBroker mountpoint, final ConfigCommand command, byte retryCounter) {
182 LOG.trace("Netconf WRITE transaction started. RetryCounter: {}", retryCounter);
183 Preconditions.checkNotNull(mountpoint);
184 final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction();
186 command.execute(rwTx);
187 final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
189 LOG.trace("Netconf WRITE transaction done for command {}", command);
191 } catch (Exception e) {
193 if (retryCounter > 0) {
194 LOG.warn("Netconf WRITE transaction failed to {}. Restarting transaction ... ", e.getMessage());
195 return write(mountpoint, command, --retryCounter);
197 LOG.warn("Netconf WRITE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
204 * Write data to remote device. Transaction is restarted if failed
206 * @param mountpoint to access remote device
207 * @param iid data identifier
208 * @param data to write
209 * @param retryCounter number of attempts
210 * @param <T> generic data type. Has to be child of {@link DataObject}
211 * @return true if transaction is successful, false otherwise
213 private static <T extends DataObject> boolean write(final DataBroker mountpoint, final InstanceIdentifier<T> iid,
214 final T data, byte retryCounter) {
215 LOG.trace("Netconf WRITE transaction started. RetryCounter: {}", retryCounter);
216 Preconditions.checkNotNull(mountpoint);
217 final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction();
219 rwTx.put(LogicalDatastoreType.CONFIGURATION, iid, data, true);
220 final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
222 LOG.trace("Netconf WRITE transaction done for {}", iid);
224 } catch (Exception e) {
226 if (retryCounter > 0) {
227 LOG.warn("Netconf WRITE transaction failed to {}. Restarting transaction ... ", e.getMessage());
228 return write(mountpoint, iid, data, --retryCounter);
230 LOG.warn("Netconf WRITE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
237 * Merge data to remote device. Transaction is restarted if failed
239 * @param mountpoint to access remote device
240 * @param iid data identifier
241 * @param data to merge
242 * @param retryCounter number of attempts
243 * @param <T> generic data type. Has to be child of {@link DataObject}
244 * @return true if transaction is successful, false otherwise
246 private static <T extends DataObject> boolean merge(final DataBroker mountpoint, final InstanceIdentifier<T> iid,
247 final T data, byte retryCounter) {
248 LOG.trace("Netconf MERGE transaction started. RetryCounter: {}", retryCounter);
249 Preconditions.checkNotNull(mountpoint);
250 final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction();
252 rwTx.merge(LogicalDatastoreType.CONFIGURATION, iid, data, true);
253 final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
255 LOG.trace("Netconf MERGE transaction done for {}", iid);
257 } catch (Exception e) {
259 if (retryCounter > 0) {
260 LOG.warn("Netconf MERGE transaction failed to {}. Restarting transaction ... ", e.getMessage());
261 return write(mountpoint, iid, data, --retryCounter);
263 LOG.warn("Netconf MERGE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
269 private static <T extends DataObject> boolean write(final DataBroker mountpoint,
270 @Nonnull final Map<InstanceIdentifier<T>, T> data, byte retryCounter) {
271 LOG.trace("Netconf WRITE transaction started. RetryCounter: {}", retryCounter);
272 Preconditions.checkNotNull(mountpoint);
273 Preconditions.checkNotNull(data);
274 Preconditions.checkArgument(!data.isEmpty());
275 final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction();
277 data.forEach((k, v) -> {
278 rwTx.put(LogicalDatastoreType.CONFIGURATION, k, v);
280 final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
282 LOG.trace("Netconf WRITE transaction done for {}",
283 data.keySet().stream().map(iid -> iid.getPathArguments()));
285 } catch (Exception e) {
287 if (retryCounter > 0) {
288 LOG.warn("Netconf WRITE transaction failed to {}. Restarting transaction ... ", e.getMessage());
289 return write(mountpoint, data, --retryCounter);
291 LOG.warn("Netconf WRITE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
298 * Read data from remote device. Transaction is restarted if failed.
300 * @param datastoreType {@link LogicalDatastoreType}
301 * @param vppIid destination node
302 * @param iid data identifier
303 * @param retryCounter number of attempts
304 * @param <T> generic data type. Has to be child of {@link DataObject}
305 * @return optional data object if successful, {@link Optional#absent()} if failed
307 public static synchronized <T extends DataObject> Optional<T> read(final InstanceIdentifier<Node> vppIid,
308 final LogicalDatastoreType datastoreType, final InstanceIdentifier<T> iid, byte retryCounter) {
309 LOG.trace("Netconf READ transaction started. RetryCounter: {}", retryCounter);
310 Preconditions.checkNotNull(vppIid);
311 DataBroker mountpoint = VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getKey();
312 final ReadOnlyTransaction rTx = mountpoint.newReadOnlyTransaction();
315 final CheckedFuture<Optional<T>, ReadFailedException> futureData =
316 rTx.read(datastoreType, iid);
317 data = futureData.get();
318 LOG.trace("Netconf READ transaction done. Data present: {}", data.isPresent());
320 } catch (Exception e) {
322 if (retryCounter > 0) {
323 LOG.warn("Netconf READ transaction failed to {}. Restarting transaction ... ", e.getMessage());
325 return read(vppIid, datastoreType, iid, --retryCounter);
327 LOG.warn("Netconf READ transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
328 return Optional.absent();
334 * Remove data from remote device using {@link ConfigCommand}
335 * @param vppIid destination node
336 * @param command config command with data, datastore type and iid
337 * @param retryCounter number of attempts
338 * @return true if transaction is successful, false otherwise
340 private static boolean deleteIfExists(final InstanceIdentifier<Node> vppIid, final AbstractInterfaceCommand command, byte retryCounter) {
341 Preconditions.checkNotNull(vppIid);
342 InstanceIdentifier<Interface> iid = VppIidFactory.getInterfaceIID(command.getInterfaceBuilder().getKey());
343 return deleteIfExists(vppIid, iid, retryCounter);
347 * Remove data from remote device. Data presence is verified before removal. Transaction is restarted if failed.
348 * @param vppIid destination node
349 * @param iid data identifier
350 * @param retryCounter number of attempts
351 * @param <T> generic data type. Has to be child of {@link DataObject}
352 * @return true if transaction is successful, false otherwise
354 private static <T extends DataObject> boolean deleteIfExists(final InstanceIdentifier<Node> vppIid,
355 final InstanceIdentifier<T> iid, byte retryCounter) {
356 LOG.trace("Netconf DELETE transaction started. Data will be read at first. RetryCounter: {}", retryCounter);
357 Preconditions.checkNotNull(vppIid);
358 DataBroker mountpoint = VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getKey();
359 final Optional<T> optionalObject = read(vppIid, LogicalDatastoreType.CONFIGURATION, iid, RETRY_COUNT);
360 if (!optionalObject.isPresent()) {
361 LOG.warn("Netconf DELETE transaction aborted. Data to remove are not present or cannot be read. Iid: {}",
363 // Return true, this state is not considered as an error
366 final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction();
368 rwTx.delete(LogicalDatastoreType.CONFIGURATION, iid);
369 final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
371 LOG.trace("Netconf DELETE transaction done for {}", iid);
373 } catch (Exception e) {
375 if (retryCounter > 0) {
376 LOG.warn("Netconf DELETE transaction failed to {}. Restarting transaction ... ", e.getMessage());
377 return deleteIfExists(vppIid, iid, --retryCounter);
379 LOG.warn("Netconf DELETE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
385 private static <T extends DataObject> boolean deleteIfExists(final InstanceIdentifier<Node> vppIid,
386 final Set<InstanceIdentifier<T>> iids, byte retryCounter) {
387 LOG.trace("Netconf DELETE transaction started. Data will be read at first. RetryCounter: {}", retryCounter);
388 Preconditions.checkNotNull(vppIid);
389 final ReadWriteTransaction rwTx = VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getKey().newReadWriteTransaction();
390 for (InstanceIdentifier<T> iid : iids) {
391 short microReadRetries = 3;
392 while (microReadRetries > 0) {
394 if (rwTx.read(LogicalDatastoreType.CONFIGURATION, iid).get().isPresent()) {
395 rwTx.delete(LogicalDatastoreType.CONFIGURATION, iid);
397 LOG.warn("Node {} does not exist. It won't be removed.", iid.getPathArguments());
401 } catch (InterruptedException | ExecutionException e) {
402 LOG.warn("Failed to read {}. Retrying... ", iid.getPathArguments());
408 final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
410 LOG.trace("Netconf DELETE transaction done for {}", iids);
412 } catch (Exception e) {
414 if (retryCounter > 0) {
415 LOG.warn("Netconf DELETE transaction failed to {}. Restarting transaction ... ", e.getMessage());
416 return deleteIfExists(vppIid, iids, --retryCounter);
418 LOG.warn("Netconf DELETE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);