2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.groupbasedpolicy.renderer.vpp.util;
11 import javax.annotation.Nonnull;
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.groupbasedpolicy.renderer.vpp.commands.lisp.AbstractLispCommand;
23 import org.opendaylight.vbd.impl.transaction.VbdNetconfTransaction;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
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;
30 import com.google.common.base.Optional;
31 import com.google.common.base.Preconditions;
32 import com.google.common.util.concurrent.CheckedFuture;
34 public class GbpNetconfTransaction {
36 public static final byte RETRY_COUNT = 3;
37 private static final Logger LOG = LoggerFactory.getLogger(GbpNetconfTransaction.class);
40 * Netconf wrapper for write and delete operation on a Netconf Device
41 * @param mountpoint netconf device
42 * @param iid path for Data to be written to
43 * @param data data to be written
44 * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails
45 * @param <T> data type
46 * @return true if transaction is successful, false otherwise
48 public static <T extends DataObject> boolean netconfSyncedWrite(@Nonnull final DataBroker mountpoint,
49 @Nonnull final InstanceIdentifier<T> iid, @Nonnull final T data, byte retryCounter) {
50 VbdNetconfTransaction.REENTRANT_LOCK.lock();
51 boolean result = write(mountpoint, iid, data, retryCounter);
52 VbdNetconfTransaction.REENTRANT_LOCK.unlock();
57 * Netconf wrapper for merge operation on a Netconf Device
58 * @param mountpoint netconf device
59 * @param iid path for Data to be merged to
60 * @param data data to be merged
61 * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails
62 * @param <T> data type
63 * @return true if transaction is successful, false otherwise
65 public static <T extends DataObject> boolean netconfSyncedMerge(@Nonnull final DataBroker mountpoint,
66 @Nonnull final InstanceIdentifier<T> iid, @Nonnull final T data, byte retryCounter) {
67 VbdNetconfTransaction.REENTRANT_LOCK.lock();
68 boolean result = merge(mountpoint, iid, data, retryCounter);
69 VbdNetconfTransaction.REENTRANT_LOCK.unlock();
74 * Netconf wrapper method for synced requests for write operation on a Netconf Device
75 * @param mountpoint netconf device
76 * @param command config command that needs to be executed
77 * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails
78 * @return true if transaction is successful, false otherwise
80 public static boolean netconfSyncedWrite(@Nonnull final DataBroker mountpoint, @Nonnull final ConfigCommand command,
82 VbdNetconfTransaction.REENTRANT_LOCK.lock();
83 boolean result = write(mountpoint, command, retryCounter);
84 VbdNetconfTransaction.REENTRANT_LOCK.unlock();
89 * Netconf wrapper method for synced requests for write operation on a Netconf Device
90 * @param mountpoint netconf device
91 * @param command abstract lisp command that needs to be executed
92 * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails
93 * @return true if transaction is successful, false otherwise
95 public static <T extends DataObject> boolean netconfSyncedWrite(@Nonnull final DataBroker mountpoint,
96 @Nonnull final AbstractLispCommand<T> command,
98 VbdNetconfTransaction.REENTRANT_LOCK.lock();
99 boolean result = write(mountpoint, command, retryCounter);
100 VbdNetconfTransaction.REENTRANT_LOCK.unlock();
105 * Netconf wrapper method for synced requests for delete operation on a Netconf Device
106 * @param mountpoint netconf device
107 * @param iid path for Data to be written to
108 * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails
109 * @param <T> data type
110 * @return true if transaction is successful, false otherwise
112 public static <T extends DataObject> boolean netconfSyncedDelete(@Nonnull final DataBroker mountpoint,
113 @Nonnull final InstanceIdentifier<T> iid, byte retryCounter) {
114 VbdNetconfTransaction.REENTRANT_LOCK.lock();
115 boolean result = deleteIfExists(mountpoint, iid, retryCounter);
116 VbdNetconfTransaction.REENTRANT_LOCK.unlock();
121 * Netconf wrapper method for synced requests for delete operation on a Netconf Device
122 * @param mountpoint netconf device
123 * @param command config command that needs to be executed
124 * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails
125 * @return true if transaction is successful, false otherwise
127 public static boolean netconfSyncedDelete(@Nonnull final DataBroker mountpoint,
128 @Nonnull final AbstractInterfaceCommand command, byte retryCounter) {
129 VbdNetconfTransaction.REENTRANT_LOCK.lock();
130 boolean result = deleteIfExists(mountpoint, command, retryCounter);
131 VbdNetconfTransaction.REENTRANT_LOCK.unlock();
136 * Netconf wrapper method for synced requests for delete operation on a Netconf Device
137 * @param mountpoint netconf device
138 * @param command routing command that needs to be executed
139 * @param retryCounter retry counter, will repeat the operation for specified amount of times if transaction fails
140 * @return true if transaction is successful, false otherwise
142 public static boolean netconfSyncedDelete(@Nonnull final DataBroker mountpoint,
143 @Nonnull final AbstractConfigCommand command, byte retryCounter) {
144 VbdNetconfTransaction.REENTRANT_LOCK.lock();
145 boolean result = deleteIfExists(mountpoint, command, retryCounter);
146 VbdNetconfTransaction.REENTRANT_LOCK.unlock();
151 * Use {@link ConfigCommand} to put data into netconf transaction and submit. Transaction is restarted if failed
153 * @param mountpoint to access remote device
154 * @param command config command with data, datastore type and iid
155 * @param retryCounter number of attempts
156 * @return true if transaction is successful, false otherwise
158 private static boolean write(final DataBroker mountpoint, final ConfigCommand command, byte retryCounter) {
159 LOG.trace("Netconf WRITE transaction started. RetryCounter: {}", retryCounter);
160 Preconditions.checkNotNull(mountpoint);
161 final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction();
163 command.execute(rwTx);
164 final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
166 LOG.trace("Netconf WRITE transaction done for command {}", command);
168 } catch (Exception e) {
170 if (retryCounter > 0) {
171 LOG.warn("Netconf WRITE transaction failed to {}. Restarting transaction ... ", e.getMessage());
172 return write(mountpoint, command, --retryCounter);
174 LOG.warn("Netconf WRITE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
181 * Write data to remote device. Transaction is restarted if failed
183 * @param mountpoint to access remote device
184 * @param iid data identifier
185 * @param data to write
186 * @param retryCounter number of attempts
187 * @param <T> generic data type. Has to be child of {@link DataObject}
188 * @return true if transaction is successful, false otherwise
190 private static <T extends DataObject> boolean write(final DataBroker mountpoint, final InstanceIdentifier<T> iid,
191 final T data, byte retryCounter) {
192 LOG.trace("Netconf WRITE transaction started. RetryCounter: {}", retryCounter);
193 Preconditions.checkNotNull(mountpoint);
194 final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction();
196 rwTx.put(LogicalDatastoreType.CONFIGURATION, iid, data, true);
197 final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
199 LOG.trace("Netconf WRITE transaction done for {}", iid);
201 } catch (Exception e) {
203 if (retryCounter > 0) {
204 LOG.warn("Netconf WRITE transaction failed to {}. Restarting transaction ... ", e.getMessage());
205 return write(mountpoint, iid, data, --retryCounter);
207 LOG.warn("Netconf WRITE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
214 * Merge data to remote device. Transaction is restarted if failed
216 * @param mountpoint to access remote device
217 * @param iid data identifier
218 * @param data to merge
219 * @param retryCounter number of attempts
220 * @param <T> generic data type. Has to be child of {@link DataObject}
221 * @return true if transaction is successful, false otherwise
223 private static <T extends DataObject> boolean merge(final DataBroker mountpoint, final InstanceIdentifier<T> iid,
224 final T data, byte retryCounter) {
225 LOG.trace("Netconf MERGE transaction started. RetryCounter: {}", retryCounter);
226 Preconditions.checkNotNull(mountpoint);
227 final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction();
229 rwTx.merge(LogicalDatastoreType.CONFIGURATION, iid, data, true);
230 final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
232 LOG.trace("Netconf MERGE transaction done for {}", iid);
234 } catch (Exception e) {
236 if (retryCounter > 0) {
237 LOG.warn("Netconf MERGE transaction failed to {}. Restarting transaction ... ", e.getMessage());
238 return write(mountpoint, iid, data, --retryCounter);
240 LOG.warn("Netconf MERGE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
247 * Use {@link AbstractLispCommand} to put data into netconf transaction and submit. Transaction is restarted if failed
249 * @param mountpoint to access remote device
250 * @param command abstract lisp command with data, datastore type and iid
251 * @param retryCounter number of attempts
252 * @return true if transaction is successful, false otherwise
254 private static <T extends DataObject> boolean write(final DataBroker mountpoint,
255 final AbstractLispCommand<T> command,
257 LOG.trace("Netconf WRITE transaction started. RetryCounter: {}", retryCounter);
258 Preconditions.checkNotNull(mountpoint);
259 final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction();
261 command.execute(rwTx);
262 final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
264 LOG.trace("Netconf WRITE transaction done for command {}", command);
266 } catch (Exception e) {
268 if (retryCounter > 0) {
269 LOG.warn("Netconf WRITE transaction failed to {}. Restarting transaction ... ", e.getMessage());
271 return write(mountpoint, command, --retryCounter);
273 LOG.warn("Netconf WRITE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
280 * Read data from remote device. Transaction is restarted if failed.
282 * @param mountpoint to access remote device
283 * @param datastoreType {@link LogicalDatastoreType}
284 * @param iid data identifier
285 * @param retryCounter number of attempts
286 * @param <T> generic data type. Has to be child of {@link DataObject}
287 * @return optional data object if successful, {@link Optional#absent()} if failed
289 public static synchronized <T extends DataObject> Optional<T> read(final DataBroker mountpoint,
290 final LogicalDatastoreType datastoreType, final InstanceIdentifier<T> iid, byte retryCounter) {
291 LOG.trace("Netconf READ transaction started. RetryCounter: {}", retryCounter);
292 Preconditions.checkNotNull(mountpoint);
293 final ReadOnlyTransaction rTx = mountpoint.newReadOnlyTransaction();
296 final CheckedFuture<Optional<T>, ReadFailedException> futureData =
297 rTx.read(datastoreType, iid);
298 data = futureData.get();
299 LOG.trace("Netconf READ transaction done. Data present: {}", data.isPresent());
301 } catch (Exception e) {
303 if (retryCounter > 0) {
304 LOG.warn("Netconf READ transaction failed to {}. Restarting transaction ... ", e.getMessage());
306 return read(mountpoint, datastoreType, iid, --retryCounter);
308 LOG.warn("Netconf READ transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
309 return Optional.absent();
315 * Remove data from remote device using {@link ConfigCommand}
317 * @param mountpoint to access remote device
318 * @param command config command with data, datastore type and iid
319 * @param retryCounter number of attempts
320 * @return true if transaction is successful, false otherwise
322 private static boolean deleteIfExists(final DataBroker mountpoint,
323 final AbstractInterfaceCommand command,
325 Preconditions.checkNotNull(mountpoint);
326 InstanceIdentifier<Interface> iid = VppIidFactory.getInterfaceIID(command.getInterfaceBuilder().getKey());
327 return deleteIfExists(mountpoint, iid, retryCounter);
331 * Remove data from remote device using {@link ConfigCommand}
333 * @param mountpoint to access remote device
334 * @param command config command with data, datastore type and iid
335 * @param retryCounter number of attempts
336 * @return true if transaction is successful, false otherwise
338 private static boolean deleteIfExists(final DataBroker mountpoint, final AbstractConfigCommand command,
340 Preconditions.checkNotNull(mountpoint);
342 return deleteIfExists(mountpoint, command.getIid(), retryCounter);
346 * Remove data from remote device. Data presence is verified before removal. Transaction is restarted if failed.
348 * @param mountpoint to access remote device
349 * @param iid data identifier
350 * @param retryCounter number of attempts
351 * @param <T> generic data type. Has to be child of {@link DataObject}
352 * @return true if transaction is successful, false otherwise
354 private static <T extends DataObject> boolean deleteIfExists(final DataBroker mountpoint,
355 final InstanceIdentifier<T> iid, byte retryCounter) {
356 LOG.trace("Netconf DELETE transaction started. Data will be read at first. RetryCounter: {}", retryCounter);
357 Preconditions.checkNotNull(mountpoint);
358 final Optional<T> optionalObject = read(mountpoint, LogicalDatastoreType.CONFIGURATION, iid, RETRY_COUNT);
359 if (!optionalObject.isPresent()) {
360 LOG.warn("Netconf DELETE transaction aborted. Data to remove are not present or cannot be read. Iid: {}",
362 // Return true, this state is not considered as an error
365 final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction();
367 rwTx.delete(LogicalDatastoreType.CONFIGURATION, iid);
368 final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
370 LOG.trace("Netconf DELETE transaction done for {}", iid);
372 } catch (Exception e) {
374 if (retryCounter > 0) {
375 LOG.warn("Netconf DELETE transaction failed to {}. Restarting transaction ... ", e.getMessage());
376 return deleteIfExists(mountpoint, iid, --retryCounter);
378 LOG.warn("Netconf DELETE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);