X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=renderers%2Fvpp%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fgroupbasedpolicy%2Frenderer%2Fvpp%2Futil%2FGbpNetconfTransaction.java;h=178648286c1782df48f5efb07f21429bc5e43b1b;hb=521874598e3bea3866471f528416dde70e901183;hp=74905a4e02099a5c8249b7423005e59c2fc396a3;hpb=0afd00fcf012d3e52a0bc67701ff82f194c9a116;p=groupbasedpolicy.git diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/GbpNetconfTransaction.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/GbpNetconfTransaction.java index 74905a4e0..178648286 100644 --- a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/GbpNetconfTransaction.java +++ b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/GbpNetconfTransaction.java @@ -8,14 +8,25 @@ package org.opendaylight.groupbasedpolicy.renderer.vpp.util; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ExecutionException; + +import javax.annotation.Nonnull; + import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; -import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.ConfigCommand; +import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.AbstractInterfaceCommand; +import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.RoutingCommand; +import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.interfaces.ConfigCommand; +import org.opendaylight.vbd.impl.transaction.VbdNetconfTransaction; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; @@ -30,6 +41,150 @@ public class GbpNetconfTransaction { public static final byte RETRY_COUNT = 3; private static final Logger LOG = LoggerFactory.getLogger(GbpNetconfTransaction.class); + /*** + * Netconf wrapper for write and delete operation on a Netconf Device + * @param vppIid destination node + * @param iid path for Data to be written to + * @param data data to be written + * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails + * @param data type + * @return true if transaction is successful, false otherwise + */ + public static boolean netconfSyncedWrite(@Nonnull final InstanceIdentifier vppIid, + @Nonnull final InstanceIdentifier iid, @Nonnull final T data, byte retryCounter) { + VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock(); + boolean result = + write(VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getKey(), iid, data, retryCounter); + VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock(); + return result; + } + + public static boolean netconfSyncedWrite(@Nonnull final InstanceIdentifier vppIid, + @Nonnull final Map,T> data, byte retryCounter) { + VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock(); + boolean result = write(VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getKey(), data, retryCounter); + VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock(); + return result; + } + + /*** + * Netconf wrapper for merge operation on a Netconf Device + * @param vppIid destination node + * @param iid path for Data to be merged to + * @param data data to be merged + * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails + * @param data type + * @return true if transaction is successful, false otherwise + */ + public static boolean netconfSyncedMerge(@Nonnull final InstanceIdentifier vppIid, + @Nonnull final InstanceIdentifier iid, @Nonnull final T data, byte retryCounter) { + VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock(); + boolean result = + merge(VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getKey(), iid, data, retryCounter); + VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock(); + return result; + } + + /*** + * Netconf wrapper for merge operation on a Netconf Device + * @param vppIid destination node + * @param command config command that needs to be executed + * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails + * @return true if transaction is successful, false otherwise + */ + public static boolean netconfSyncedMerge(@Nonnull final InstanceIdentifier vppIid, + @Nonnull final ConfigCommand command, byte retryCounter) { + VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock(); + boolean result = + write(VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getKey(), command, retryCounter); + VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock(); + return result; + } + + /*** + * Netconf wrapper method for synced requests for write operation on a Netconf Device + * @param vppIid destination node + * @param command config command that needs to be executed + * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails + * @return true if transaction is successful, false otherwise + */ + public static boolean netconfSyncedWrite(@Nonnull final InstanceIdentifier vppIid, + @Nonnull final ConfigCommand command, byte retryCounter) { + VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock(); + boolean result = write(VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getKey(), command, retryCounter); + VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock(); + return result; + } + + /*** + * Netconf wrapper method for synced requests for write operation on a Netconf Device + * @param vppIid destination node + * @param command routing command that needs to be executed + * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails + * @return true if transaction is successful, false otherwise + */ + public static boolean netconfSyncedWrite(@Nonnull final InstanceIdentifier vppIid, + @Nonnull final RoutingCommand command, byte retryCounter) { + VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock(); + boolean result = write(VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getKey(), command, retryCounter); + VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock(); + return result; + } + + /*** + * Netconf wrapper method for synced requests for delete operation on a Netconf Device + * @param vppIid destination node + * @param iid path for Data to be written to + * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails + * @param data type + * @return true if transaction is successful, false otherwise + */ + public static boolean netconfSyncedDelete(@Nonnull final InstanceIdentifier vppIid, + @Nonnull final InstanceIdentifier iid, byte retryCounter) { + VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock(); + boolean result = deleteIfExists(vppIid, iid, retryCounter); + VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock(); + return result; + } + + public static boolean netconfSyncedDelete(@Nonnull final InstanceIdentifier vppIid, + @Nonnull Set> iids , byte retryCounter) { + VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock(); + boolean result = deleteIfExists(vppIid, iids, retryCounter); + VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock(); + return result; + } + + /*** + * Netconf wrapper method for synced requests for delete operation on a Netconf Device + * @param vppIid destination node + * @param command config command that needs to be executed + * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails + * @return true if transaction is successful, false otherwise + */ + public static boolean netconfSyncedDelete(@Nonnull final InstanceIdentifier vppIid, + @Nonnull final ConfigCommand command, byte retryCounter) { + VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock(); + boolean result = deleteIfExists(vppIid, command.getIid(), retryCounter); + VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock(); + return result; + } + + /*** + * Netconf wrapper method for synced requests for delete operation on a Netconf Device + * @param vppIid destination node + * @param command routing command that needs to be executed + * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails + * @return true if transaction is successful, false otherwise + */ + public static boolean netconfSyncedDelete(@Nonnull final InstanceIdentifier vppIid, + @Nonnull final RoutingCommand command, byte retryCounter) { + VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().lock(); + boolean result = deleteIfExists(vppIid, command.getIid(), retryCounter); + VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getValue().unlock(); + return result; + } + /** * Use {@link ConfigCommand} to put data into netconf transaction and submit. Transaction is restarted if failed * @@ -38,8 +193,7 @@ public class GbpNetconfTransaction { * @param retryCounter number of attempts * @return true if transaction is successful, false otherwise */ - public static synchronized boolean write(final DataBroker mountpoint, final ConfigCommand command, - byte retryCounter) { + private static boolean write(final DataBroker mountpoint, final ConfigCommand command, byte retryCounter) { LOG.trace("Netconf WRITE transaction started. RetryCounter: {}", retryCounter); Preconditions.checkNotNull(mountpoint); final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction(); @@ -71,10 +225,8 @@ public class GbpNetconfTransaction { * @param generic data type. Has to be child of {@link DataObject} * @return true if transaction is successful, false otherwise */ - public static synchronized boolean write(final DataBroker mountpoint, - final InstanceIdentifier iid, - final T data, - byte retryCounter) { + private static boolean write(final DataBroker mountpoint, final InstanceIdentifier iid, + final T data, byte retryCounter) { LOG.trace("Netconf WRITE transaction started. RetryCounter: {}", retryCounter); Preconditions.checkNotNull(mountpoint); final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction(); @@ -96,27 +248,84 @@ public class GbpNetconfTransaction { } } + /** + * Merge data to remote device. Transaction is restarted if failed + * + * @param mountpoint to access remote device + * @param iid data identifier + * @param data to merge + * @param retryCounter number of attempts + * @param generic data type. Has to be child of {@link DataObject} + * @return true if transaction is successful, false otherwise + */ + private static boolean merge(final DataBroker mountpoint, final InstanceIdentifier iid, + final T data, byte retryCounter) { + LOG.trace("Netconf MERGE transaction started. RetryCounter: {}", retryCounter); + Preconditions.checkNotNull(mountpoint); + final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction(); + try { + rwTx.merge(LogicalDatastoreType.CONFIGURATION, iid, data, true); + final CheckedFuture futureTask = rwTx.submit(); + futureTask.get(); + LOG.trace("Netconf MERGE transaction done for {}", iid); + return true; + } catch (Exception e) { + // Retry + if (retryCounter > 0) { + LOG.warn("Netconf MERGE transaction failed to {}. Restarting transaction ... ", e.getMessage()); + return write(mountpoint, iid, data, --retryCounter); + } else { + LOG.warn("Netconf MERGE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e); + return false; + } + } + } + + private static boolean write(final DataBroker mountpoint, + @Nonnull final Map, T> data, byte retryCounter) { + LOG.trace("Netconf WRITE transaction started. RetryCounter: {}", retryCounter); + Preconditions.checkNotNull(mountpoint); + Preconditions.checkNotNull(data); + Preconditions.checkArgument(!data.isEmpty()); + final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction(); + try { + data.forEach((k, v) -> rwTx.put(LogicalDatastoreType.CONFIGURATION, k, v, true)); + final CheckedFuture futureTask = rwTx.submit(); + futureTask.get(); + LOG.trace("Netconf WRITE transaction done for {}", data); + return true; + } catch (Exception e) { + // Retry + if (retryCounter > 0) { + LOG.warn("Netconf WRITE transaction failed to {}. Restarting transaction ... ", e.getMessage()); + return write(mountpoint, data, --retryCounter); + } else { + LOG.warn("Netconf WRITE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e); + return false; + } + } + } + /** * Read data from remote device. Transaction is restarted if failed. * - * @param mountpoint to access remote device * @param datastoreType {@link LogicalDatastoreType} + * @param vppIid destination node * @param iid data identifier * @param retryCounter number of attempts * @param generic data type. Has to be child of {@link DataObject} * @return optional data object if successful, {@link Optional#absent()} if failed */ - public static synchronized Optional read(final DataBroker mountpoint, - final LogicalDatastoreType datastoreType, - final InstanceIdentifier iid, - byte retryCounter) { + public static synchronized Optional read(final InstanceIdentifier vppIid, + final LogicalDatastoreType datastoreType, final InstanceIdentifier iid, byte retryCounter) { LOG.trace("Netconf READ transaction started. RetryCounter: {}", retryCounter); - Preconditions.checkNotNull(mountpoint); + Preconditions.checkNotNull(vppIid); + DataBroker mountpoint = VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getKey(); final ReadOnlyTransaction rTx = mountpoint.newReadOnlyTransaction(); Optional data; try { final CheckedFuture, ReadFailedException> futureData = - rTx.read(datastoreType, iid); + rTx.read(datastoreType, iid); data = futureData.get(); LOG.trace("Netconf READ transaction done. Data present: {}", data.isPresent()); return data; @@ -125,7 +334,7 @@ public class GbpNetconfTransaction { if (retryCounter > 0) { LOG.warn("Netconf READ transaction failed to {}. Restarting transaction ... ", e.getMessage()); rTx.close(); - return read(mountpoint, datastoreType, iid, --retryCounter); + return read(vppIid, datastoreType, iid, --retryCounter); } else { LOG.warn("Netconf READ transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e); return Optional.absent(); @@ -135,37 +344,35 @@ public class GbpNetconfTransaction { /** * Remove data from remote device using {@link ConfigCommand} - * - * @param mountpoint to access remote device + * @param vppIid destination node * @param command config command with data, datastore type and iid * @param retryCounter number of attempts * @return true if transaction is successful, false otherwise */ - public static synchronized boolean deleteIfExists(final DataBroker mountpoint, final ConfigCommand command, - byte retryCounter) { - Preconditions.checkNotNull(mountpoint); + private static boolean deleteIfExists(final InstanceIdentifier vppIid, final AbstractInterfaceCommand command, + byte retryCounter) { + Preconditions.checkNotNull(vppIid); InstanceIdentifier iid = VppIidFactory.getInterfaceIID(command.getInterfaceBuilder().getKey()); - return deleteIfExists(mountpoint, iid, retryCounter); + return deleteIfExists(vppIid, iid, retryCounter); } /** * Remove data from remote device. Data presence is verified before removal. Transaction is restarted if failed. - * - * @param mountpoint to access remote device + * @param vppIid destination node * @param iid data identifier * @param retryCounter number of attempts * @param generic data type. Has to be child of {@link DataObject} * @return true if transaction is successful, false otherwise */ - public static synchronized boolean deleteIfExists(final DataBroker mountpoint, - final InstanceIdentifier iid, - byte retryCounter) { + private static boolean deleteIfExists(final InstanceIdentifier vppIid, + final InstanceIdentifier iid, byte retryCounter) { LOG.trace("Netconf DELETE transaction started. Data will be read at first. RetryCounter: {}", retryCounter); - Preconditions.checkNotNull(mountpoint); - final Optional optionalObject = read(mountpoint, LogicalDatastoreType.CONFIGURATION, iid, RETRY_COUNT); + Preconditions.checkNotNull(vppIid); + DataBroker mountpoint = VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getKey(); + final Optional optionalObject = read(vppIid, LogicalDatastoreType.CONFIGURATION, iid, RETRY_COUNT); if (!optionalObject.isPresent()) { LOG.warn("Netconf DELETE transaction aborted. Data to remove are not present or cannot be read. Iid: {}", - iid); + iid); // Return true, this state is not considered as an error return true; } @@ -180,11 +387,53 @@ public class GbpNetconfTransaction { // Retry if (retryCounter > 0) { LOG.warn("Netconf DELETE transaction failed to {}. Restarting transaction ... ", e.getMessage()); - return deleteIfExists(mountpoint, iid, --retryCounter); + return deleteIfExists(vppIid, iid, --retryCounter); + } else { + LOG.warn("Netconf DELETE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e); + return false; + } + } + } + + private static boolean deleteIfExists(final InstanceIdentifier vppIid, + final Set> iids, byte retryCounter) { + LOG.trace("Netconf DELETE transaction started. Data will be read at first. RetryCounter: {}", retryCounter); + Preconditions.checkNotNull(vppIid); + final ReadWriteTransaction rwTx = + VbdNetconfTransaction.NODE_DATA_BROKER_MAP.get(vppIid).getKey().newReadWriteTransaction(); + Set> alreadyRemoved = new HashSet<>(); + for (InstanceIdentifier iid : iids) { + short microReadRetries = 3; + while (microReadRetries > 0) { + try { + if (rwTx.read(LogicalDatastoreType.CONFIGURATION, iid).get().isPresent()) { + rwTx.delete(LogicalDatastoreType.CONFIGURATION, iid); + } else { + LOG.warn("Node {} does not exist. It won't be removed.", iid.getPathArguments()); + alreadyRemoved.add(iid); + } + break; + } catch (InterruptedException | ExecutionException e) { + LOG.warn("Failed to read {}. Retrying... ", iid.getPathArguments()); + microReadRetries--; + } + } + } + alreadyRemoved.forEach(t -> iids.remove(t)); + try { + final CheckedFuture futureTask = rwTx.submit(); + futureTask.get(); + LOG.trace("Netconf DELETE transaction done for {}", iids); + return true; + } catch (Exception e) { + // Retry + if (retryCounter > 0) { + LOG.warn("Netconf DELETE transaction failed to {}. Restarting transaction ... ", e.getMessage()); + return deleteIfExists(vppIid, iids, --retryCounter); } else { LOG.warn("Netconf DELETE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e); return false; } } } -} \ No newline at end of file +}