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