better odl <-> device communication via netconf - gbp side 67/51067/5
authorVladimir Lavor <vlavor@cisco.com>
Thu, 26 Jan 2017 13:13:59 +0000 (14:13 +0100)
committerVladimir Lavor <vlavor@cisco.com>
Tue, 31 Jan 2017 11:17:12 +0000 (12:17 +0100)
* transaction is restarted after every exception (caused by
  collision, netconf failure, HC failure etc.)
* data to remove are verified whether they are present to
  prevent netconf transaction exceptions

Change-Id: I7243b174cb1545f78d2df897e8755fc173e3757a
Signed-off-by: Vladimir Lavor <vlavor@cisco.com>
renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/iface/InterfaceManager.java
renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/GbpNetconfTransaction.java
renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/GbpNetconfTransactionTest.java

index bba5f19e44a7aea9a1525e178f0729f67b647e5b..ac6cc065aa5a8107aab7465e894c2f266f4b03a5 100644 (file)
@@ -191,7 +191,7 @@ public class InterfaceManager implements AutoCloseable {
 
     private ListenableFuture<Void> deleteIfaceOnVpp(ConfigCommand deleteIfaceWithoutBdCommand,
             DataBroker vppDataBroker, VppEndpoint vppEndpoint, InstanceIdentifier<?> vppNodeIid) {
-        final boolean transactionState = GbpNetconfTransaction.delete(vppDataBroker, deleteIfaceWithoutBdCommand,
+        final boolean transactionState = GbpNetconfTransaction.deleteIfExists(vppDataBroker, deleteIfaceWithoutBdCommand,
                 GbpNetconfTransaction.RETRY_COUNT);
         if (transactionState) {
             LOG.debug("Delete interface on VPP command was successful: VPP: {} Command: {}", vppNodeIid,
@@ -408,7 +408,7 @@ public class InterfaceManager implements AutoCloseable {
             LOG.warn("Interface already not in bridge domain {} ", ifaceKey);
             return Futures.immediateFuture(null);
         }
-        final boolean transactionState = GbpNetconfTransaction.delete(mountPoint,
+        final boolean transactionState = GbpNetconfTransaction.deleteIfExists(mountPoint,
                 VppIidFactory.getL2ForInterfaceIid(ifaceKey), GbpNetconfTransaction.RETRY_COUNT);
         if (transactionState) {
             LOG.debug("Removing bridge domain from interface {}", VppIidFactory.getInterfaceIID(ifaceKey));
@@ -484,7 +484,7 @@ public class InterfaceManager implements AutoCloseable {
         InstanceIdentifier<L2> l2Iid =
                 interfaceIid.builder().augmentation(VppInterfaceAugmentation.class).child(L2.class).build();
         LOG.debug("Deleting bridge domain from interface {}", interfacePath);
-        final boolean transactionState = GbpNetconfTransaction.delete(mountpoint, l2Iid,
+        final boolean transactionState = GbpNetconfTransaction.deleteIfExists(mountpoint, l2Iid,
                 GbpNetconfTransaction.RETRY_COUNT);
         if (transactionState) {
             return vppEndpointLocationProvider.replaceLocationForEndpoint(new ExternalLocationCaseBuilder()
index f0e820daaf1810f95b5b0dc955b1cbfdaff113a1..ac4d715f6f0f2054c5715bb313c98cf0c6b9005c 100644 (file)
@@ -18,6 +18,7 @@ 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.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;
@@ -25,7 +26,7 @@ import org.slf4j.LoggerFactory;
 
 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);
 
     /**
@@ -36,7 +37,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,
+    public static synchronized boolean write(final DataBroker mountpoint, final ConfigCommand command,
                                              byte retryCounter) {
         LOG.trace("Netconf WRITE transaction started. RetryCounter: {}", retryCounter);
         Preconditions.checkNotNull(mountpoint);
@@ -45,20 +46,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 +70,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,
+    public static synchronized <T extends DataObject> boolean write(final DataBroker mountpoint,
                                                                     final InstanceIdentifier<T> iid,
                                                                     final T data,
                                                                     byte retryCounter) {
@@ -83,20 +81,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 +105,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 +117,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,
+    public static synchronized 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 +156,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,
+    public static synchronized <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;
         }
     }
-
-}
+}
\ No newline at end of file
index 29e33ca437a39a1d5589a770cbaf64355093547a..7fa27d596da4f639227fc80f98b950822039d608 100644 (file)
@@ -19,6 +19,7 @@ import static org.mockito.Mockito.when;
 
 import com.google.common.base.Optional;
 import com.google.common.util.concurrent.CheckedFuture;
+import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
@@ -27,6 +28,10 @@ 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.LoopbackCommand;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
@@ -35,6 +40,8 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
 public class GbpNetconfTransactionTest {
 
+    private final String INTERFACE_KEY = "interface-key";
+    private final String NODE_ID = "node-id";
     private final DataBroker dataBroker = mock(DataBroker.class);
     private final ReadWriteTransaction rwTx = mock(ReadWriteTransaction.class);
     private final ReadOnlyTransaction rTx = mock(ReadOnlyTransaction.class);
@@ -45,22 +52,19 @@ public class GbpNetconfTransactionTest {
     private final CheckedFuture<Void, TransactionCommitFailedException> future = mock(CheckedFuture.class);
     @SuppressWarnings("unchecked")
     private final CheckedFuture<Optional<Node>, ReadFailedException> futureNode = mock(CheckedFuture.class);
-    private final ConfigCommand command = mock(ConfigCommand.class);
+    @SuppressWarnings("unchecked")
+    private final CheckedFuture<Optional<Interface>, ReadFailedException> futureInterface = mock(CheckedFuture.class);
+    private final ConfigCommand command = mock(LoopbackCommand.class);
+    private final InterfaceBuilder interfaceBuilder = new InterfaceBuilder().setKey(new InterfaceKey(INTERFACE_KEY));
 
-    @Test
-    public void writeConfigCommandExceptionTest() {
+    @Before
+    public void init() {
+        when(dataBroker.newReadOnlyTransaction()).thenReturn(rTx);
         when(dataBroker.newReadWriteTransaction()).thenReturn(rwTx);
-        doThrow(new RuntimeException()).when(command).execute(rwTx);
-
-        final boolean result = GbpNetconfTransaction.write(dataBroker, command, (byte)5);
-        verify(dataBroker, times(1)).newReadWriteTransaction();
-        assertFalse(result);
-
     }
 
     @Test
     public void writeConfigCommandReattemptTest() {
-        when(dataBroker.newReadWriteTransaction()).thenReturn(rwTx);
         doThrow(new IllegalStateException()).when(command).execute(rwTx);
 
         final boolean result = GbpNetconfTransaction.write(dataBroker, command, (byte)5);
@@ -70,7 +74,6 @@ public class GbpNetconfTransactionTest {
 
     @Test
     public void writeConfigCommandTest() throws Exception {
-        when(dataBroker.newReadWriteTransaction()).thenReturn(rwTx);
         when(rwTx.submit()).thenReturn(future);
         doNothing().when(command).execute(rwTx);
         when(future.get()).thenReturn(null);
@@ -80,19 +83,8 @@ public class GbpNetconfTransactionTest {
         assertTrue(result);
     }
 
-    @Test
-    public void writeDataExceptionTest() {
-        when(dataBroker.newReadWriteTransaction()).thenReturn(rwTx);
-        doThrow(new RuntimeException()).when(rwTx).put(LogicalDatastoreType.CONFIGURATION, nodeIid, node, true);
-
-        final boolean result = GbpNetconfTransaction.write(dataBroker, nodeIid, node, (byte)5);
-        verify(dataBroker, times(1)).newReadWriteTransaction();
-        assertFalse(result);
-    }
-
     @Test
     public void writeDataReattemptTest() {
-        when(dataBroker.newReadWriteTransaction()).thenReturn(rwTx);
         doThrow(new IllegalStateException()).when(rwTx).put(LogicalDatastoreType.CONFIGURATION, nodeIid, node, true);
 
         final boolean result = GbpNetconfTransaction.write(dataBroker, nodeIid, node, (byte)5);
@@ -102,7 +94,6 @@ public class GbpNetconfTransactionTest {
 
     @Test
     public void writeDataTest() throws Exception {
-        when(dataBroker.newReadWriteTransaction()).thenReturn(rwTx);
         when(rwTx.submit()).thenReturn(future);
         doNothing().when(rwTx).put(LogicalDatastoreType.CONFIGURATION, nodeIid, node, true);
         when(future.get()).thenReturn(null);
@@ -112,20 +103,8 @@ public class GbpNetconfTransactionTest {
         assertTrue(result);
     }
 
-    @Test
-    public void readDataExceptionTest() {
-        when(dataBroker.newReadOnlyTransaction()).thenReturn(rTx);
-        doThrow(new RuntimeException()).when(rTx).read(LogicalDatastoreType.CONFIGURATION, nodeIid);
-
-        final Optional<Node> result = GbpNetconfTransaction.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
-                nodeIid, (byte)5);
-        verify(dataBroker, times(1)).newReadOnlyTransaction();
-        assertFalse(result.isPresent());
-    }
-
     @Test
     public void readDataReattemptTest() {
-        when(dataBroker.newReadOnlyTransaction()).thenReturn(rTx);
         doThrow(new IllegalStateException()).when(rTx).read(LogicalDatastoreType.CONFIGURATION, nodeIid);
 
         final Optional<Node> result = GbpNetconfTransaction.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
@@ -136,10 +115,9 @@ public class GbpNetconfTransactionTest {
 
     @Test
     public void readDataTest() throws Exception {
-        when(dataBroker.newReadOnlyTransaction()).thenReturn(rTx);
         when(rTx.read(LogicalDatastoreType.CONFIGURATION, nodeIid)).thenReturn(futureNode);
         when(futureNode.get()).thenReturn(Optional.of(new NodeBuilder()
-                .setKey(new NodeKey(new NodeId("node"))).build()));
+                .setKey(new NodeKey(new NodeId(NODE_ID))).build()));
 
         final Optional<Node> result = GbpNetconfTransaction.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
                 nodeIid, (byte)5);
@@ -148,65 +126,81 @@ public class GbpNetconfTransactionTest {
     }
 
     @Test
-    public void deleteConfigCommandExceptionTest() {
-        when(dataBroker.newReadWriteTransaction()).thenReturn(rwTx);
-        doThrow(new RuntimeException()).when(command).execute(rwTx);
+    public void deleteConfigCommandMissingDataTest() throws Exception {
+        final InstanceIdentifier<Interface> iid = VppIidFactory.getInterfaceIID(interfaceBuilder.getKey());
+        when(command.getInterfaceBuilder()).thenReturn(interfaceBuilder);
+        when(rTx.read(LogicalDatastoreType.CONFIGURATION, iid)).thenReturn(futureInterface);
+        when(futureInterface.get()).thenReturn(Optional.absent());
+        doThrow(new IllegalStateException()).when(command).execute(rwTx);
 
-        final boolean result = GbpNetconfTransaction.delete(dataBroker, command, (byte)5);
-        verify(dataBroker, times(1)).newReadWriteTransaction();
-        assertFalse(result);
+        final boolean result = GbpNetconfTransaction.deleteIfExists(dataBroker, command, (byte)5);
+        verify(dataBroker, times(1)).newReadOnlyTransaction();
+        assertTrue(result);
     }
 
     @Test
-    public void deleteConfigCommandReattemptTest() {
-        when(dataBroker.newReadWriteTransaction()).thenReturn(rwTx);
+    public void deleteConfigCommandReattemptTest() throws Exception {
+        final InstanceIdentifier<Interface> iid = VppIidFactory.getInterfaceIID(interfaceBuilder.getKey());
+        when(command.getInterfaceBuilder()).thenReturn(interfaceBuilder);
+        when(rTx.read(LogicalDatastoreType.CONFIGURATION, iid)).thenReturn(futureInterface);
+        when(futureInterface.get()).thenReturn(Optional.of(new InterfaceBuilder()
+                .setKey(new InterfaceKey(INTERFACE_KEY)).build()));
         doThrow(new IllegalStateException()).when(command).execute(rwTx);
 
-        final boolean result = GbpNetconfTransaction.delete(dataBroker, command, (byte)5);
+        final boolean result = GbpNetconfTransaction.deleteIfExists(dataBroker, command, (byte)5);
         verify(dataBroker, times(6)).newReadWriteTransaction();
         assertFalse(result);
     }
 
     @Test
     public void deleteConfigCommandTest() throws Exception {
-        when(dataBroker.newReadWriteTransaction()).thenReturn(rwTx);
+        final InstanceIdentifier<Interface> iid = VppIidFactory.getInterfaceIID(interfaceBuilder.getKey());
+        when(command.getInterfaceBuilder()).thenReturn(interfaceBuilder);
+        when(rTx.read(LogicalDatastoreType.CONFIGURATION, iid)).thenReturn(futureInterface);
+        when(futureInterface.get()).thenReturn(Optional.of(new InterfaceBuilder()
+                .setKey(new InterfaceKey(INTERFACE_KEY)).build()));
         when(rwTx.submit()).thenReturn(future);
         doNothing().when(command).execute(rwTx);
         when(future.get()).thenReturn(null);
 
-        final boolean result = GbpNetconfTransaction.delete(dataBroker, command, (byte)5);
+        final boolean result = GbpNetconfTransaction.deleteIfExists(dataBroker, command, (byte)5);
         verify(dataBroker, times(1)).newReadWriteTransaction();
         assertTrue(result);
     }
 
     @Test
-    public void deleteDataExceptionTest() {
-        when(dataBroker.newReadWriteTransaction()).thenReturn(rwTx);
-        doThrow(new RuntimeException()).when(rwTx).delete(LogicalDatastoreType.CONFIGURATION, nodeIid);
+    public void deleteDataMissingDataTest() throws Exception {
+        when(rTx.read(LogicalDatastoreType.CONFIGURATION, nodeIid)).thenReturn(futureNode);
+        when(futureNode.get()).thenReturn(Optional.absent());
+        doThrow(new IllegalStateException()).when(command).execute(rwTx);
 
-        final boolean result = GbpNetconfTransaction.delete(dataBroker, nodeIid, (byte)5);
-        verify(dataBroker, times(1)).newReadWriteTransaction();
-        assertFalse(result);
+        final boolean result = GbpNetconfTransaction.deleteIfExists(dataBroker, nodeIid, (byte)5);
+        verify(dataBroker, times(1)).newReadOnlyTransaction();
+        assertTrue(result);
     }
 
     @Test
-    public void deleteDataReattemptTest() {
-        when(dataBroker.newReadWriteTransaction()).thenReturn(rwTx);
+    public void deleteDataReattemptTest() throws Exception {
+        when(rTx.read(LogicalDatastoreType.CONFIGURATION, nodeIid)).thenReturn(futureNode);
+        when(futureNode.get()).thenReturn(Optional.of(new NodeBuilder()
+                .setKey(new NodeKey(new NodeId(NODE_ID))).build()));
         doThrow(new IllegalStateException()).when(rwTx).delete(LogicalDatastoreType.CONFIGURATION, nodeIid);
 
-        final boolean result = GbpNetconfTransaction.delete(dataBroker, nodeIid, (byte)5);
+        final boolean result = GbpNetconfTransaction.deleteIfExists(dataBroker, nodeIid, (byte)5);
         verify(dataBroker, times(6)).newReadWriteTransaction();
         assertFalse(result);
     }
 
     @Test
     public void deleteDataTest() throws Exception {
-        when(dataBroker.newReadWriteTransaction()).thenReturn(rwTx);
+        when(rTx.read(LogicalDatastoreType.CONFIGURATION, nodeIid)).thenReturn(futureNode);
+        when(futureNode.get()).thenReturn(Optional.of(new NodeBuilder()
+                .setKey(new NodeKey(new NodeId(NODE_ID))).build()));
         when(rwTx.submit()).thenReturn(future);
         doNothing().when(rwTx).delete(LogicalDatastoreType.CONFIGURATION, nodeIid);
         when(future.get()).thenReturn(null);
 
-        final boolean result = GbpNetconfTransaction.delete(dataBroker, nodeIid, (byte)5);
+        final boolean result = GbpNetconfTransaction.deleteIfExists(dataBroker, nodeIid, (byte)5);
         verify(dataBroker, times(1)).newReadWriteTransaction();
         assertTrue(result);
     }