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;
11 import java.util.HashSet;
14 import java.util.concurrent.ExecutionException;
16 import javax.annotation.Nonnull;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
20 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
23 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
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.vbd.impl.transaction.VbdNetconfTransaction;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
29 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
30 import org.opendaylight.yangtools.yang.binding.DataObject;
31 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
35 import com.google.common.base.Optional;
36 import com.google.common.base.Preconditions;
37 import com.google.common.util.concurrent.CheckedFuture;
39 public class GbpNetconfTransaction {
41 public static final byte RETRY_COUNT = 3;
42 private static final Logger LOG = LoggerFactory.getLogger(GbpNetconfTransaction.class);
45 * Netconf wrapper for write and delete operation on a Netconf Device
46 * @param vppIid destination node
47 * @param iid path for Data to be written to
48 * @param data data to be written
49 * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails
50 * @param <T> data type
51 * @return true if transaction is successful, false otherwise
53 public static <T extends DataObject> boolean netconfSyncedWrite(@Nonnull final InstanceIdentifier<Node> vppIid,
54 @Nonnull final InstanceIdentifier<T> iid, @Nonnull final T data, byte retryCounter) {
55 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock();
56 boolean result = write(VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getKey(), iid, data, retryCounter);
57 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock();
61 public static <T extends DataObject> boolean netconfSyncedWrite(@Nonnull final InstanceIdentifier<Node> vppIid,
62 @Nonnull final Map<InstanceIdentifier<T>,T> data, byte retryCounter) {
63 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock();
64 boolean result = write(VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getKey(), data, retryCounter);
65 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock();
70 * Netconf wrapper for merge operation on a Netconf Device
71 * @param vppIid destination node
72 * @param iid path for Data to be merged to
73 * @param data data to be merged
74 * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails
75 * @param <T> data type
76 * @return true if transaction is successful, false otherwise
78 public static <T extends DataObject> boolean netconfSyncedMerge(@Nonnull final InstanceIdentifier<Node> vppIid,
79 @Nonnull final InstanceIdentifier<T> iid, @Nonnull final T data, byte retryCounter) {
80 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock();
81 boolean result = merge(VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getKey(), iid, data, retryCounter);
82 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock();
87 * Netconf wrapper method for synced requests for write operation on a Netconf Device
88 * @param vppIid destination node
89 * @param command config command that needs to be executed
90 * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails
91 * @return true if transaction is successful, false otherwise
93 public static boolean netconfSyncedWrite(@Nonnull final InstanceIdentifier<Node> vppIid, @Nonnull final ConfigCommand command,
95 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock();
96 boolean result = write(VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getKey(), command, retryCounter);
97 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock();
102 * Netconf wrapper method for synced requests for write operation on a Netconf Device
103 * @param vppIid destination node
104 * @param command routing command that needs to be executed
105 * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails
106 * @return true if transaction is successful, false otherwise
108 public static boolean netconfSyncedWrite(@Nonnull final InstanceIdentifier<Node> vppIid, @Nonnull final RoutingCommand command,
110 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock();
111 boolean result = write(VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getKey(), command, retryCounter);
112 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock();
117 * Netconf wrapper method for synced requests for delete operation on a Netconf Device
118 * @param vppIid destination node
119 * @param iid path for Data to be written to
120 * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails
121 * @param <T> data type
122 * @return true if transaction is successful, false otherwise
124 public static <T extends DataObject> boolean netconfSyncedDelete(@Nonnull final InstanceIdentifier<Node> vppIid,
125 @Nonnull final InstanceIdentifier<T> iid, byte retryCounter) {
126 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock();
127 boolean result = deleteIfExists(vppIid, iid, retryCounter);
128 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock();
132 public static <T extends DataObject> boolean netconfSyncedDelete(@Nonnull final InstanceIdentifier<Node> vppIid,
133 @Nonnull Set<InstanceIdentifier<T>> iids , byte retryCounter) {
134 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock();
135 boolean result = deleteIfExists(vppIid, iids, retryCounter);
136 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock();
141 * Netconf wrapper method for synced requests for delete operation on a Netconf Device
142 * @param vppIid destination node
143 * @param command config command that needs to be executed
144 * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails
145 * @return true if transaction is successful, false otherwise
147 public static boolean netconfSyncedDelete(@Nonnull final InstanceIdentifier<Node> vppIid,
148 @Nonnull final ConfigCommand command, byte retryCounter) {
149 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock();
150 boolean result = deleteIfExists(vppIid, command.getIid(), retryCounter);
151 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock();
156 * Netconf wrapper method for synced requests for delete operation on a Netconf Device
157 * @param vppIid destination node
158 * @param command routing command that needs to be executed
159 * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails
160 * @return true if transaction is successful, false otherwise
162 public static boolean netconfSyncedDelete(@Nonnull final InstanceIdentifier<Node> vppIid,
163 @Nonnull final RoutingCommand command, byte retryCounter) {
164 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock();
165 boolean result = deleteIfExists(vppIid, command.getIid(), retryCounter);
166 VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock();
171 * Use {@link ConfigCommand} to put data into netconf transaction and submit. Transaction is restarted if failed
173 * @param mountpoint to access remote device
174 * @param command config command with data, datastore type and iid
175 * @param retryCounter number of attempts
176 * @return true if transaction is successful, false otherwise
178 private static boolean write(final DataBroker mountpoint, final ConfigCommand command, byte retryCounter) {
179 LOG.trace("Netconf WRITE transaction started. RetryCounter: {}", retryCounter);
180 Preconditions.checkNotNull(mountpoint);
181 final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction();
183 command.execute(rwTx);
184 final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
186 LOG.trace("Netconf WRITE transaction done for command {}", command);
188 } catch (Exception e) {
190 if (retryCounter > 0) {
191 LOG.warn("Netconf WRITE transaction failed to {}. Restarting transaction ... ", e.getMessage());
192 return write(mountpoint, command, --retryCounter);
194 LOG.warn("Netconf WRITE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
201 * Write data to remote device. Transaction is restarted if failed
203 * @param mountpoint to access remote device
204 * @param iid data identifier
205 * @param data to write
206 * @param retryCounter number of attempts
207 * @param <T> generic data type. Has to be child of {@link DataObject}
208 * @return true if transaction is successful, false otherwise
210 private static <T extends DataObject> boolean write(final DataBroker mountpoint, final InstanceIdentifier<T> iid,
211 final T data, byte retryCounter) {
212 LOG.trace("Netconf WRITE transaction started. RetryCounter: {}", retryCounter);
213 Preconditions.checkNotNull(mountpoint);
214 final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction();
216 rwTx.put(LogicalDatastoreType.CONFIGURATION, iid, data, true);
217 final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
219 LOG.trace("Netconf WRITE transaction done for {}", iid);
221 } catch (Exception e) {
223 if (retryCounter > 0) {
224 LOG.warn("Netconf WRITE transaction failed to {}. Restarting transaction ... ", e.getMessage());
225 return write(mountpoint, iid, data, --retryCounter);
227 LOG.warn("Netconf WRITE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
234 * Merge data to remote device. Transaction is restarted if failed
236 * @param mountpoint to access remote device
237 * @param iid data identifier
238 * @param data to merge
239 * @param retryCounter number of attempts
240 * @param <T> generic data type. Has to be child of {@link DataObject}
241 * @return true if transaction is successful, false otherwise
243 private static <T extends DataObject> boolean merge(final DataBroker mountpoint, final InstanceIdentifier<T> iid,
244 final T data, byte retryCounter) {
245 LOG.trace("Netconf MERGE transaction started. RetryCounter: {}", retryCounter);
246 Preconditions.checkNotNull(mountpoint);
247 final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction();
249 rwTx.merge(LogicalDatastoreType.CONFIGURATION, iid, data, true);
250 final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
252 LOG.trace("Netconf MERGE transaction done for {}", iid);
254 } catch (Exception e) {
256 if (retryCounter > 0) {
257 LOG.warn("Netconf MERGE transaction failed to {}. Restarting transaction ... ", e.getMessage());
258 return write(mountpoint, iid, data, --retryCounter);
260 LOG.warn("Netconf MERGE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
266 private static <T extends DataObject> boolean write(final DataBroker mountpoint,
267 @Nonnull final Map<InstanceIdentifier<T>, T> data, byte retryCounter) {
268 LOG.trace("Netconf WRITE transaction started. RetryCounter: {}", retryCounter);
269 Preconditions.checkNotNull(mountpoint);
270 Preconditions.checkNotNull(data);
271 Preconditions.checkArgument(!data.isEmpty());
272 final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction();
274 data.forEach((k, v) -> {
275 rwTx.put(LogicalDatastoreType.CONFIGURATION, k, v, true);
277 final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
279 LOG.trace("Netconf WRITE transaction done for {}",
280 data.keySet().stream().map(iid -> iid.getPathArguments()));
282 } catch (Exception e) {
284 if (retryCounter > 0) {
285 LOG.warn("Netconf WRITE transaction failed to {}. Restarting transaction ... ", e.getMessage());
286 return write(mountpoint, data, --retryCounter);
288 LOG.warn("Netconf WRITE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
295 * Read data from remote device. Transaction is restarted if failed.
297 * @param datastoreType {@link LogicalDatastoreType}
298 * @param vppIid destination node
299 * @param iid data identifier
300 * @param retryCounter number of attempts
301 * @param <T> generic data type. Has to be child of {@link DataObject}
302 * @return optional data object if successful, {@link Optional#absent()} if failed
304 public static synchronized <T extends DataObject> Optional<T> read(final InstanceIdentifier<Node> vppIid,
305 final LogicalDatastoreType datastoreType, final InstanceIdentifier<T> iid, byte retryCounter) {
306 LOG.trace("Netconf READ transaction started. RetryCounter: {}", retryCounter);
307 Preconditions.checkNotNull(vppIid);
308 DataBroker mountpoint = VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getKey();
309 final ReadOnlyTransaction rTx = mountpoint.newReadOnlyTransaction();
312 final CheckedFuture<Optional<T>, ReadFailedException> futureData =
313 rTx.read(datastoreType, iid);
314 data = futureData.get();
315 LOG.trace("Netconf READ transaction done. Data present: {}", data.isPresent());
317 } catch (Exception e) {
319 if (retryCounter > 0) {
320 LOG.warn("Netconf READ transaction failed to {}. Restarting transaction ... ", e.getMessage());
322 return read(vppIid, datastoreType, iid, --retryCounter);
324 LOG.warn("Netconf READ transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
325 return Optional.absent();
331 * Remove data from remote device using {@link ConfigCommand}
332 * @param vppIid destination node
333 * @param command config command with data, datastore type and iid
334 * @param retryCounter number of attempts
335 * @return true if transaction is successful, false otherwise
337 private static boolean deleteIfExists(final InstanceIdentifier<Node> vppIid, final AbstractInterfaceCommand command, byte retryCounter) {
338 Preconditions.checkNotNull(vppIid);
339 InstanceIdentifier<Interface> iid = VppIidFactory.getInterfaceIID(command.getInterfaceBuilder().getKey());
340 return deleteIfExists(vppIid, iid, retryCounter);
344 * Remove data from remote device. Data presence is verified before removal. Transaction is restarted if failed.
345 * @param vppIid destination node
346 * @param iid data identifier
347 * @param retryCounter number of attempts
348 * @param <T> generic data type. Has to be child of {@link DataObject}
349 * @return true if transaction is successful, false otherwise
351 private static <T extends DataObject> boolean deleteIfExists(final InstanceIdentifier<Node> vppIid,
352 final InstanceIdentifier<T> iid, byte retryCounter) {
353 LOG.trace("Netconf DELETE transaction started. Data will be read at first. RetryCounter: {}", retryCounter);
354 Preconditions.checkNotNull(vppIid);
355 DataBroker mountpoint = VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getKey();
356 final Optional<T> optionalObject = read(vppIid, LogicalDatastoreType.CONFIGURATION, iid, RETRY_COUNT);
357 if (!optionalObject.isPresent()) {
358 LOG.warn("Netconf DELETE transaction aborted. Data to remove are not present or cannot be read. Iid: {}",
360 // Return true, this state is not considered as an error
363 final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction();
365 rwTx.delete(LogicalDatastoreType.CONFIGURATION, iid);
366 final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
368 LOG.trace("Netconf DELETE transaction done for {}", iid);
370 } catch (Exception e) {
372 if (retryCounter > 0) {
373 LOG.warn("Netconf DELETE transaction failed to {}. Restarting transaction ... ", e.getMessage());
374 return deleteIfExists(vppIid, iid, --retryCounter);
376 LOG.warn("Netconf DELETE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
382 private static <T extends DataObject> boolean deleteIfExists(final InstanceIdentifier<Node> vppIid,
383 final Set<InstanceIdentifier<T>> iids, byte retryCounter) {
384 LOG.trace("Netconf DELETE transaction started. Data will be read at first. RetryCounter: {}", retryCounter);
385 Preconditions.checkNotNull(vppIid);
386 final ReadWriteTransaction rwTx = VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getKey().newReadWriteTransaction();
387 Set<InstanceIdentifier<T>> alreadyRemoved = new HashSet<>();
388 for (InstanceIdentifier<T> iid : iids) {
389 short microReadRetries = 3;
390 while (microReadRetries > 0) {
392 if (rwTx.read(LogicalDatastoreType.CONFIGURATION, iid).get().isPresent()) {
393 rwTx.delete(LogicalDatastoreType.CONFIGURATION, iid);
395 LOG.warn("Node {} does not exist. It won't be removed.", iid.getPathArguments());
396 alreadyRemoved.add(iid);
399 } catch (InterruptedException | ExecutionException e) {
400 LOG.warn("Failed to read {}. Retrying... ", iid.getPathArguments());
405 alreadyRemoved.forEach(t -> {
409 final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
411 LOG.trace("Netconf DELETE transaction done for {}", iids);
413 } catch (Exception e) {
415 if (retryCounter > 0) {
416 LOG.warn("Netconf DELETE transaction failed to {}. Restarting transaction ... ", e.getMessage());
417 return deleteIfExists(vppIid, iids, --retryCounter);
419 LOG.warn("Netconf DELETE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);