Merge "Implemented unregister l3-prefix endpoint"
[groupbasedpolicy.git] / renderers / vpp / src / main / java / org / opendaylight / groupbasedpolicy / renderer / vpp / util / GbpNetconfTransaction.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.groupbasedpolicy.renderer.vpp.util;
10
11 import javax.annotation.Nonnull;
12
13 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
14 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
15 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
16 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
17 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
18 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
19 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.ConfigCommand;
20 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.RoutingCommand;
21 import org.opendaylight.vbd.impl.transaction.VbdNetconfTransaction;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocol;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocolKey;
25 import org.opendaylight.yangtools.yang.binding.DataObject;
26 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 import com.google.common.base.Optional;
31 import com.google.common.base.Preconditions;
32 import com.google.common.base.Strings;
33 import com.google.common.util.concurrent.CheckedFuture;
34
35 public class GbpNetconfTransaction {
36
37     public static final byte RETRY_COUNT = 3;
38     private static final Logger LOG = LoggerFactory.getLogger(GbpNetconfTransaction.class);
39
40     /***
41      * Netconf wrapper for write and delete operation on a Netconf Device
42      * @param mountpoint    netconf device
43      * @param iid           path for Data to be written to
44      * @param data          data to be written
45      * @param retryCounter  retry counter, will repeat the operation for specified amount of times if transaction fails
46      * @param <T>           data type
47      * @return true if transaction is successful, false otherwise
48      */
49     public static <T extends DataObject> boolean netconfSyncedWrite(@Nonnull final DataBroker mountpoint,
50         @Nonnull final InstanceIdentifier<T> iid, @Nonnull final T data, byte retryCounter) {
51         VbdNetconfTransaction.REENTRANT_LOCK.lock();
52         boolean result = write(mountpoint, iid, data, retryCounter);
53         VbdNetconfTransaction.REENTRANT_LOCK.unlock();
54         return result;
55     }
56
57     /***
58      * Netconf wrapper method for synced requests for write operation on a Netconf Device
59      * @param mountpoint    netconf device
60      * @param command       config command that needs to be executed
61      * @param retryCounter  retry counter, will repeat the operation for specified amount of times if transaction fails
62      * @return true if transaction is successful, false otherwise
63      */
64     public static boolean netconfSyncedWrite(@Nonnull final DataBroker mountpoint, @Nonnull final ConfigCommand command,
65         byte retryCounter) {
66         VbdNetconfTransaction.REENTRANT_LOCK.lock();
67         boolean result = write(mountpoint, command, retryCounter);
68         VbdNetconfTransaction.REENTRANT_LOCK.unlock();
69         return result;
70     }
71
72     /***
73      * Netconf wrapper method for synced requests for write operation on a Netconf Device
74      * @param mountpoint    netconf device
75      * @param command       routing command that needs to be executed
76      * @param retryCounter  retry counter, will repeat the operation for specified amount of times if transaction fails
77      * @return true if transaction is successful, false otherwise
78      */
79     public static boolean netconfSyncedWrite(@Nonnull final DataBroker mountpoint, @Nonnull final RoutingCommand command,
80         byte retryCounter) {
81         VbdNetconfTransaction.REENTRANT_LOCK.lock();
82         boolean result = write(mountpoint, command, retryCounter);
83         VbdNetconfTransaction.REENTRANT_LOCK.unlock();
84         return result;
85     }
86
87     /***
88      * Netconf wrapper method for synced requests for delete operation on a Netconf Device
89      * @param mountpoint    netconf device
90      * @param iid           path for Data to be written to
91      * @param retryCounter  retry counter, will repeat the operation for specified amount of times if transaction fails
92      * @param <T>           data type
93      * @return true if transaction is successful, false otherwise
94      */
95     public static <T extends DataObject> boolean netconfSyncedDelete(@Nonnull final DataBroker mountpoint,
96         @Nonnull final InstanceIdentifier<T> iid, byte retryCounter) {
97         VbdNetconfTransaction.REENTRANT_LOCK.lock();
98         boolean result = deleteIfExists(mountpoint, iid, retryCounter);
99         VbdNetconfTransaction.REENTRANT_LOCK.unlock();
100         return result;
101     }
102
103     /***
104      * Netconf wrapper method for synced requests for delete operation on a Netconf Device
105      * @param mountpoint    netconf device
106      * @param command       config command that needs to be executed
107      * @param retryCounter  retry counter, will repeat the operation for specified amount of times if transaction fails
108      * @return true if transaction is successful, false otherwise
109      */
110     public static boolean netconfSyncedDelete(@Nonnull final DataBroker mountpoint,
111         @Nonnull final ConfigCommand command, byte retryCounter) {
112         VbdNetconfTransaction.REENTRANT_LOCK.lock();
113         boolean result = deleteIfExists(mountpoint, command, retryCounter);
114         VbdNetconfTransaction.REENTRANT_LOCK.unlock();
115         return result;
116     }
117
118     /***
119      * Netconf wrapper method for synced requests for delete operation on a Netconf Device
120      * @param mountpoint    netconf device
121      * @param command       routing command that needs to be executed
122      * @param retryCounter  retry counter, will repeat the operation for specified amount of times if transaction fails
123      * @return true if transaction is successful, false otherwise
124      */
125     public static boolean netconfSyncedDelete(@Nonnull final DataBroker mountpoint,
126         @Nonnull final RoutingCommand command, byte retryCounter) {
127         VbdNetconfTransaction.REENTRANT_LOCK.lock();
128         boolean result = deleteIfExists(mountpoint, command, retryCounter);
129         VbdNetconfTransaction.REENTRANT_LOCK.unlock();
130         return result;
131     }
132
133     /**
134      * Use {@link ConfigCommand} to put data into netconf transaction and submit. Transaction is restarted if failed
135      *
136      * @param mountpoint   to access remote device
137      * @param command      config command with data, datastore type and iid
138      * @param retryCounter number of attempts
139      * @return true if transaction is successful, false otherwise
140      */
141     private static boolean write(final DataBroker mountpoint, final ConfigCommand command, byte retryCounter) {
142         LOG.trace("Netconf WRITE transaction started. RetryCounter: {}", retryCounter);
143         Preconditions.checkNotNull(mountpoint);
144         final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction();
145         try {
146             command.execute(rwTx);
147             final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
148             futureTask.get();
149             LOG.trace("Netconf WRITE transaction done for command {}", command);
150             return true;
151         } catch (Exception e) {
152             // Retry
153             if (retryCounter > 0) {
154                 LOG.warn("Netconf WRITE transaction failed to {}. Restarting transaction ... ", e.getMessage());
155                 return write(mountpoint, command, --retryCounter);
156             } else {
157                 LOG.warn("Netconf WRITE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
158                 return false;
159             }
160         }
161     }
162
163     /**
164      * Use {@link RoutingCommand} to put data into netconf transaction and submit. Transaction is restarted if failed
165      *
166      * @param mountpoint   to access remote device
167      * @param command      routing command with data, datastore type and iid
168      * @param retryCounter number of attempts
169      * @return true if transaction is successful, false otherwise
170      */
171     private static boolean write(final DataBroker mountpoint, final RoutingCommand command, byte retryCounter) {
172         LOG.trace("Netconf WRITE transaction started. RetryCounter: {}", retryCounter);
173         Preconditions.checkNotNull(mountpoint);
174         final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction();
175         try {
176             command.execute(rwTx);
177             final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
178             futureTask.get();
179             LOG.trace("Netconf WRITE transaction done for command {}", command);
180             return true;
181         } catch (Exception e) {
182             // Retry
183             if (retryCounter > 0) {
184                 LOG.warn("Netconf WRITE transaction failed to {}. Restarting transaction ... ", e.getMessage());
185                 return write(mountpoint, command, --retryCounter);
186             } else {
187                 LOG.warn("Netconf WRITE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
188                 return false;
189             }
190         }
191     }
192
193     /**
194      * Write data to remote device. Transaction is restarted if failed
195      *
196      * @param mountpoint   to access remote device
197      * @param iid          data identifier
198      * @param data         to write
199      * @param retryCounter number of attempts
200      * @param <T>          generic data type. Has to be child of {@link DataObject}
201      * @return true if transaction is successful, false otherwise
202      */
203     private static <T extends DataObject> boolean write(final DataBroker mountpoint, final InstanceIdentifier<T> iid,
204         final T data, byte retryCounter) {
205         LOG.trace("Netconf WRITE transaction started. RetryCounter: {}", retryCounter);
206         Preconditions.checkNotNull(mountpoint);
207         final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction();
208         try {
209             rwTx.put(LogicalDatastoreType.CONFIGURATION, iid, data, true);
210             final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
211             futureTask.get();
212             LOG.trace("Netconf WRITE transaction done for {}", iid);
213             return true;
214         } catch (Exception e) {
215             // Retry
216             if (retryCounter > 0) {
217                 LOG.warn("Netconf WRITE transaction failed to {}. Restarting transaction ... ", e.getMessage());
218                 return write(mountpoint, iid, data, --retryCounter);
219             } else {
220                 LOG.warn("Netconf WRITE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
221                 return false;
222             }
223         }
224     }
225
226     /**
227      * Read data from remote device. Transaction is restarted if failed.
228      *
229      * @param mountpoint    to access remote device
230      * @param datastoreType {@link LogicalDatastoreType}
231      * @param iid           data identifier
232      * @param retryCounter  number of attempts
233      * @param <T>           generic data type. Has to be child of {@link DataObject}
234      * @return optional data object if successful, {@link Optional#absent()} if failed
235      */
236     public static synchronized <T extends DataObject> Optional<T> read(final DataBroker mountpoint,
237         final LogicalDatastoreType datastoreType, final InstanceIdentifier<T> iid, byte retryCounter) {
238         LOG.trace("Netconf READ transaction started. RetryCounter: {}", retryCounter);
239         Preconditions.checkNotNull(mountpoint);
240         final ReadOnlyTransaction rTx = mountpoint.newReadOnlyTransaction();
241         Optional<T> data;
242         try {
243             final CheckedFuture<Optional<T>, ReadFailedException> futureData =
244                 rTx.read(datastoreType, iid);
245             data = futureData.get();
246             LOG.trace("Netconf READ transaction done. Data present: {}", data.isPresent());
247             return data;
248         } catch (Exception e) {
249             // Retry
250             if (retryCounter > 0) {
251                 LOG.warn("Netconf READ transaction failed to {}. Restarting transaction ... ", e.getMessage());
252                 rTx.close();
253                 return read(mountpoint, datastoreType, iid, --retryCounter);
254             } else {
255                 LOG.warn("Netconf READ transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
256                 return Optional.absent();
257             }
258         }
259     }
260
261     /**
262      * Remove data from remote device using {@link ConfigCommand}
263      *
264      * @param mountpoint   to access remote device
265      * @param command      config command with data, datastore type and iid
266      * @param retryCounter number of attempts
267      * @return true if transaction is successful, false otherwise
268      */
269     private static boolean deleteIfExists(final DataBroker mountpoint, final ConfigCommand command, byte retryCounter) {
270         Preconditions.checkNotNull(mountpoint);
271         InstanceIdentifier<Interface> iid = VppIidFactory.getInterfaceIID(command.getInterfaceBuilder().getKey());
272         return deleteIfExists(mountpoint, iid, retryCounter);
273     }
274
275     /**
276      * Remove data from remote device using {@link ConfigCommand}
277      *
278      * @param mountpoint   to access remote device
279      * @param command      config command with data, datastore type and iid
280      * @param retryCounter number of attempts
281      * @return true if transaction is successful, false otherwise
282      */
283     private static boolean deleteIfExists(final DataBroker mountpoint, final RoutingCommand command,
284         byte retryCounter) {
285         Preconditions.checkNotNull(mountpoint);
286         String routerProtocol = command.getRouterProtocol();
287         if (Strings.isNullOrEmpty(routerProtocol)) {
288             routerProtocol = "learned-protocol-0";
289         }
290         InstanceIdentifier<RoutingProtocol> iid =
291             VppIidFactory.getRoutingInstanceIid(new RoutingProtocolKey(routerProtocol));
292         return deleteIfExists(mountpoint, iid, retryCounter);
293     }
294
295     /**
296      * Remove data from remote device. Data presence is verified before removal. Transaction is restarted if failed.
297      *
298      * @param mountpoint   to access remote device
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 true if transaction is successful, false otherwise
303      */
304     private static <T extends DataObject> boolean deleteIfExists(final DataBroker mountpoint,
305         final InstanceIdentifier<T> iid, byte retryCounter) {
306         LOG.trace("Netconf DELETE transaction started. Data will be read at first. RetryCounter: {}", retryCounter);
307         Preconditions.checkNotNull(mountpoint);
308         final Optional<T> optionalObject = read(mountpoint, LogicalDatastoreType.CONFIGURATION, iid, RETRY_COUNT);
309         if (!optionalObject.isPresent()) {
310             LOG.warn("Netconf DELETE transaction aborted. Data to remove are not present or cannot be read. Iid: {}",
311                 iid);
312             // Return true, this state is not considered as an error
313             return true;
314         }
315         final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction();
316         try {
317             rwTx.delete(LogicalDatastoreType.CONFIGURATION, iid);
318             final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
319             futureTask.get();
320             LOG.trace("Netconf DELETE transaction done for {}", iid);
321             return true;
322         } catch (Exception e) {
323             // Retry
324             if (retryCounter > 0) {
325                 LOG.warn("Netconf DELETE transaction failed to {}. Restarting transaction ... ", e.getMessage());
326                 return deleteIfExists(mountpoint, iid, --retryCounter);
327             } else {
328                 LOG.warn("Netconf DELETE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
329                 return false;
330             }
331         }
332     }
333 }