Netconf transactions synchronization GBP part
[groupbasedpolicy.git] / renderers / vpp / src / main / java / org / opendaylight / groupbasedpolicy / renderer / vpp / util / GbpNetconfTransaction.java
index f0e820daaf1810f95b5b0dc955b1cbfdaff113a1..12f5b6acf3d7322e1563e4ad03015dbd53a13617 100644 (file)
@@ -8,9 +8,8 @@
 
 package org.opendaylight.groupbasedpolicy.renderer.vpp.util;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.util.concurrent.CheckedFuture;
+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;
@@ -18,16 +17,86 @@ 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.vbd.impl.transaction.VbdNetconfTransaction;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+
 public class GbpNetconfTransaction {
 
-    public static final byte RETRY_COUNT = 5;
+    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 mountpoint    netconf device
+     * @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 <T>           data type
+     * @return true if transaction is successful, false otherwise
+     */
+    public static <T extends DataObject> boolean netconfSyncedWrite(@Nonnull final DataBroker mountpoint,
+        @Nonnull final InstanceIdentifier<T> iid, @Nonnull final T data, byte retryCounter) {
+        VbdNetconfTransaction.REENTRANT_LOCK.lock();
+        boolean result = write(mountpoint, iid, data, retryCounter);
+        VbdNetconfTransaction.REENTRANT_LOCK.unlock();
+        return result;
+    }
+
+    /***
+     * Netconf wrapper method for synced requests for write operation on a Netconf Device
+     * @param mountpoint    netconf device
+     * @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 DataBroker mountpoint, @Nonnull final ConfigCommand command,
+        byte retryCounter) {
+        VbdNetconfTransaction.REENTRANT_LOCK.lock();
+        boolean result = write(mountpoint, command, retryCounter);
+        VbdNetconfTransaction.REENTRANT_LOCK.unlock();
+        return result;
+    }
+
+    /***
+     * Netconf wrapper method for synced requests for delete operation on a Netconf Device
+     * @param mountpoint    netconf device
+     * @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 <T>           data type
+     * @return true if transaction is successful, false otherwise
+     */
+    public static <T extends DataObject> boolean netconfSyncedDelete(@Nonnull final DataBroker mountpoint,
+        @Nonnull final InstanceIdentifier<T> iid, byte retryCounter) {
+        VbdNetconfTransaction.REENTRANT_LOCK.lock();
+        boolean result = deleteIfExists(mountpoint, iid, retryCounter);
+        VbdNetconfTransaction.REENTRANT_LOCK.unlock();
+        return result;
+    }
+
+    /***
+     * Netconf wrapper method for synced requests for delete operation on a Netconf Device
+     * @param mountpoint    netconf device
+     * @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 DataBroker mountpoint,
+        @Nonnull final ConfigCommand command, byte retryCounter) {
+        VbdNetconfTransaction.REENTRANT_LOCK.lock();
+        boolean result = deleteIfExists(mountpoint, command, retryCounter);
+        VbdNetconfTransaction.REENTRANT_LOCK.unlock();
+        return result;
+    }
+
+
     /**
      * Use {@link ConfigCommand} to put data into netconf transaction and submit. Transaction is restarted if failed
      *
@@ -36,8 +105,7 @@ public class GbpNetconfTransaction {
      * @param retryCounter number of attempts
      * @return true if transaction is successful, false otherwise
      */
-    public synchronized static 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();
@@ -45,20 +113,17 @@ public class GbpNetconfTransaction {
             command.execute(rwTx);
             final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
             futureTask.get();
-            LOG.trace("Netconf WRITE transaction done. Retry counter: {}", retryCounter);
+            LOG.trace("Netconf WRITE transaction done for command {}", command);
             return true;
-        } catch (IllegalStateException e) {
+        } catch (Exception e) {
             // Retry
             if (retryCounter > 0) {
-                LOG.warn("Assuming that netconf write-transaction failed, restarting ...", e.getMessage());
+                LOG.warn("Netconf WRITE transaction failed to {}. Restarting transaction ... ", e.getMessage());
                 return write(mountpoint, command, --retryCounter);
             } else {
-                LOG.warn("Netconf write-transaction failed. Maximal number of attempts reached", e.getMessage());
+                LOG.warn("Netconf WRITE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
                 return false;
             }
-        } catch (Exception e) {
-            LOG.warn("Exception while writing data ...", e.getMessage());
-            return false;
         }
     }
 
@@ -72,7 +137,7 @@ public class GbpNetconfTransaction {
      * @param <T>          generic data type. Has to be child of {@link DataObject}
      * @return true if transaction is successful, false otherwise
      */
-    public synchronized static <T extends DataObject> boolean write(final DataBroker mountpoint,
+    private static <T extends DataObject> boolean write(final DataBroker mountpoint,
                                                                     final InstanceIdentifier<T> iid,
                                                                     final T data,
                                                                     byte retryCounter) {
@@ -83,20 +148,17 @@ public class GbpNetconfTransaction {
             rwTx.put(LogicalDatastoreType.CONFIGURATION, iid, data, true);
             final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
             futureTask.get();
-            LOG.trace("Netconf WRITE transaction done. Retry counter: {}", retryCounter);
+            LOG.trace("Netconf WRITE transaction done for {}", iid);
             return true;
-        } catch (IllegalStateException e) {
+        } catch (Exception e) {
             // Retry
             if (retryCounter > 0) {
-                LOG.warn("Assuming that netconf write-transaction failed, restarting ...", e.getMessage());
+                LOG.warn("Netconf WRITE transaction failed to {}. Restarting transaction ... ", e.getMessage());
                 return write(mountpoint, iid, data, --retryCounter);
             } else {
-                LOG.warn("Netconf write-transaction failed. Maximal number of attempts reached", e.getMessage());
+                LOG.warn("Netconf WRITE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
                 return false;
             }
-        } catch (Exception e) {
-            LOG.warn("Exception while writing data ...", e.getMessage());
-            return false;
         }
     }
 
@@ -110,7 +172,7 @@ public class GbpNetconfTransaction {
      * @param <T>           generic data type. Has to be child of {@link DataObject}
      * @return optional data object if successful, {@link Optional#absent()} if failed
      */
-    public synchronized static <T extends DataObject> Optional<T> read(final DataBroker mountpoint,
+    public static synchronized <T extends DataObject> Optional<T> read(final DataBroker mountpoint,
                                                                        final LogicalDatastoreType datastoreType,
                                                                        final InstanceIdentifier<T> iid,
                                                                        byte retryCounter) {
@@ -122,61 +184,38 @@ public class GbpNetconfTransaction {
             final CheckedFuture<Optional<T>, ReadFailedException> futureData =
                     rTx.read(datastoreType, iid);
             data = futureData.get();
-            LOG.trace("Netconf READ transaction done. Data present: {}, Retry counter: {}",
-                    data.isPresent(), retryCounter);
+            LOG.trace("Netconf READ transaction done. Data present: {}", data.isPresent());
             return data;
-        } catch (IllegalStateException e) {
+        } catch (Exception e) {
             // Retry
             if (retryCounter > 0) {
-                LOG.warn("Assuming that netconf read-transaction failed, restarting ...", e.getMessage());
+                LOG.warn("Netconf READ transaction failed to {}. Restarting transaction ... ", e.getMessage());
                 rTx.close();
                 return read(mountpoint, datastoreType, iid, --retryCounter);
             } else {
-                LOG.warn("Netconf read-transaction failed. Maximal number of attempts reached", e.getMessage());
+                LOG.warn("Netconf READ transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
                 return Optional.absent();
             }
-        } catch (Exception e) {
-            LOG.warn("Exception while reading data ...", e.getMessage());
-            return Optional.absent();
         }
     }
 
     /**
-     * Remove data from remote device using {@link ConfigCommand}. Transaction is restarted if failed.
+     * Remove data from remote device using {@link ConfigCommand}
      *
      * @param mountpoint   to access remote device
      * @param command      config command with data, datastore type and iid
      * @param retryCounter number of attempts
      * @return true if transaction is successful, false otherwise
      */
-    public synchronized static boolean delete(final DataBroker mountpoint, final ConfigCommand command,
+    private static boolean deleteIfExists(final DataBroker mountpoint, final ConfigCommand command,
                                               byte retryCounter) {
-        LOG.trace("Netconf DELETE transaction started. RetryCounter: {}", retryCounter);
         Preconditions.checkNotNull(mountpoint);
-        final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction();
-        try {
-            command.execute(rwTx);
-            final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
-            futureTask.get();
-            LOG.trace("Netconf DELETE transaction done. Retry counter: {}", retryCounter);
-            return true;
-        } catch (IllegalStateException e) {
-            // Retry
-            if (retryCounter > 0) {
-                LOG.warn("Assuming that netconf delete-transaction failed, restarting ...", e.getMessage());
-                return delete(mountpoint, command, --retryCounter);
-            } else {
-                LOG.warn("Netconf delete-transaction failed. Maximal number of attempts reached", e.getMessage());
-                return false;
-            }
-        } catch (Exception e) {
-            LOG.warn("Exception while removing data ...", e.getMessage());
-            return false;
-        }
+        InstanceIdentifier<Interface> iid = VppIidFactory.getInterfaceIID(command.getInterfaceBuilder().getKey());
+        return deleteIfExists(mountpoint, iid, retryCounter);
     }
 
     /**
-     * Remove data from remote device. Transaction is restarted if failed.
+     * Remove data from remote device. Data presence is verified before removal. Transaction is restarted if failed.
      *
      * @param mountpoint   to access remote device
      * @param iid          data identifier
@@ -184,31 +223,34 @@ public class GbpNetconfTransaction {
      * @param <T>          generic data type. Has to be child of {@link DataObject}
      * @return true if transaction is successful, false otherwise
      */
-    public synchronized static <T extends DataObject> boolean delete(final DataBroker mountpoint,
+    private static <T extends DataObject> boolean deleteIfExists(final DataBroker mountpoint,
                                                                      final InstanceIdentifier<T> iid,
                                                                      byte retryCounter) {
-        LOG.trace("Netconf DELETE transaction started. RetryCounter: {}", retryCounter);
+        LOG.trace("Netconf DELETE transaction started. Data will be read at first. RetryCounter: {}", retryCounter);
         Preconditions.checkNotNull(mountpoint);
+        final Optional<T> optionalObject = read(mountpoint, 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);
+            // Return true, this state is not considered as an error
+            return true;
+        }
         final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction();
         try {
             rwTx.delete(LogicalDatastoreType.CONFIGURATION, iid);
             final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
             futureTask.get();
-            LOG.trace("Netconf DELETE transaction done. Retry counter: {}", retryCounter);
+            LOG.trace("Netconf DELETE transaction done for {}", iid);
             return true;
-        } catch (IllegalStateException e) {
+        } catch (Exception e) {
             // Retry
             if (retryCounter > 0) {
-                LOG.warn("Assuming that netconf delete-transaction failed, restarting ...", e.getMessage());
-                return delete(mountpoint, iid, --retryCounter);
+                LOG.warn("Netconf DELETE transaction failed to {}. Restarting transaction ... ", e.getMessage());
+                return deleteIfExists(mountpoint, iid, --retryCounter);
             } else {
-                LOG.warn("Netconf delete-transaction failed. Maximal number of attempts reached", e.getMessage());
+                LOG.warn("Netconf DELETE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
                 return false;
             }
-        } catch (Exception e) {
-            LOG.warn("Exception while removing data ...", e.getMessage());
-            return false;
         }
     }
-
 }