better odl <-> device communication via netconf - gbp side
[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 com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import com.google.common.util.concurrent.CheckedFuture;
14 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
15 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
16 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
17 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
18 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
19 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
20 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.ConfigCommand;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
22 import org.opendaylight.yangtools.yang.binding.DataObject;
23 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 public class GbpNetconfTransaction {
28
29     public static final byte RETRY_COUNT = 3;
30     private static final Logger LOG = LoggerFactory.getLogger(GbpNetconfTransaction.class);
31
32     /**
33      * Use {@link ConfigCommand} to put data into netconf transaction and submit. Transaction is restarted if failed
34      *
35      * @param mountpoint   to access remote device
36      * @param command      config command with data, datastore type and iid
37      * @param retryCounter number of attempts
38      * @return true if transaction is successful, false otherwise
39      */
40     public static synchronized boolean write(final DataBroker mountpoint, final ConfigCommand command,
41                                              byte retryCounter) {
42         LOG.trace("Netconf WRITE transaction started. RetryCounter: {}", retryCounter);
43         Preconditions.checkNotNull(mountpoint);
44         final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction();
45         try {
46             command.execute(rwTx);
47             final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
48             futureTask.get();
49             LOG.trace("Netconf WRITE transaction done for command {}", command);
50             return true;
51         } catch (Exception e) {
52             // Retry
53             if (retryCounter > 0) {
54                 LOG.warn("Netconf WRITE transaction failed to {}. Restarting transaction ... ", e.getMessage());
55                 return write(mountpoint, command, --retryCounter);
56             } else {
57                 LOG.warn("Netconf WRITE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
58                 return false;
59             }
60         }
61     }
62
63     /**
64      * Write data to remote device. Transaction is restarted if failed
65      *
66      * @param mountpoint   to access remote device
67      * @param iid          data identifier
68      * @param data         to write
69      * @param retryCounter number of attempts
70      * @param <T>          generic data type. Has to be child of {@link DataObject}
71      * @return true if transaction is successful, false otherwise
72      */
73     public static synchronized <T extends DataObject> boolean write(final DataBroker mountpoint,
74                                                                     final InstanceIdentifier<T> iid,
75                                                                     final T data,
76                                                                     byte retryCounter) {
77         LOG.trace("Netconf WRITE transaction started. RetryCounter: {}", retryCounter);
78         Preconditions.checkNotNull(mountpoint);
79         final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction();
80         try {
81             rwTx.put(LogicalDatastoreType.CONFIGURATION, iid, data, true);
82             final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
83             futureTask.get();
84             LOG.trace("Netconf WRITE transaction done for {}", iid);
85             return true;
86         } catch (Exception e) {
87             // Retry
88             if (retryCounter > 0) {
89                 LOG.warn("Netconf WRITE transaction failed to {}. Restarting transaction ... ", e.getMessage());
90                 return write(mountpoint, iid, data, --retryCounter);
91             } else {
92                 LOG.warn("Netconf WRITE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
93                 return false;
94             }
95         }
96     }
97
98     /**
99      * Read data from remote device. Transaction is restarted if failed.
100      *
101      * @param mountpoint    to access remote device
102      * @param datastoreType {@link LogicalDatastoreType}
103      * @param iid           data identifier
104      * @param retryCounter  number of attempts
105      * @param <T>           generic data type. Has to be child of {@link DataObject}
106      * @return optional data object if successful, {@link Optional#absent()} if failed
107      */
108     public static synchronized <T extends DataObject> Optional<T> read(final DataBroker mountpoint,
109                                                                        final LogicalDatastoreType datastoreType,
110                                                                        final InstanceIdentifier<T> iid,
111                                                                        byte retryCounter) {
112         LOG.trace("Netconf READ transaction started. RetryCounter: {}", retryCounter);
113         Preconditions.checkNotNull(mountpoint);
114         final ReadOnlyTransaction rTx = mountpoint.newReadOnlyTransaction();
115         Optional<T> data;
116         try {
117             final CheckedFuture<Optional<T>, ReadFailedException> futureData =
118                     rTx.read(datastoreType, iid);
119             data = futureData.get();
120             LOG.trace("Netconf READ transaction done. Data present: {}", data.isPresent());
121             return data;
122         } catch (Exception e) {
123             // Retry
124             if (retryCounter > 0) {
125                 LOG.warn("Netconf READ transaction failed to {}. Restarting transaction ... ", e.getMessage());
126                 rTx.close();
127                 return read(mountpoint, datastoreType, iid, --retryCounter);
128             } else {
129                 LOG.warn("Netconf READ transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
130                 return Optional.absent();
131             }
132         }
133     }
134
135     /**
136      * Remove data from remote device using {@link ConfigCommand}
137      *
138      * @param mountpoint   to access remote device
139      * @param command      config command with data, datastore type and iid
140      * @param retryCounter number of attempts
141      * @return true if transaction is successful, false otherwise
142      */
143     public static synchronized boolean deleteIfExists(final DataBroker mountpoint, final ConfigCommand command,
144                                               byte retryCounter) {
145         Preconditions.checkNotNull(mountpoint);
146         InstanceIdentifier<Interface> iid = VppIidFactory.getInterfaceIID(command.getInterfaceBuilder().getKey());
147         return deleteIfExists(mountpoint, iid, retryCounter);
148     }
149
150     /**
151      * Remove data from remote device. Data presence is verified before removal. Transaction is restarted if failed.
152      *
153      * @param mountpoint   to access remote device
154      * @param iid          data identifier
155      * @param retryCounter number of attempts
156      * @param <T>          generic data type. Has to be child of {@link DataObject}
157      * @return true if transaction is successful, false otherwise
158      */
159     public static synchronized <T extends DataObject> boolean deleteIfExists(final DataBroker mountpoint,
160                                                                      final InstanceIdentifier<T> iid,
161                                                                      byte retryCounter) {
162         LOG.trace("Netconf DELETE transaction started. Data will be read at first. RetryCounter: {}", retryCounter);
163         Preconditions.checkNotNull(mountpoint);
164         final Optional<T> optionalObject = read(mountpoint, LogicalDatastoreType.CONFIGURATION, iid, RETRY_COUNT);
165         if (!optionalObject.isPresent()) {
166             LOG.warn("Netconf DELETE transaction aborted. Data to remove are not present or cannot be read. Iid: {}",
167                     iid);
168             // Return true, this state is not considered as an error
169             return true;
170         }
171         final ReadWriteTransaction rwTx = mountpoint.newReadWriteTransaction();
172         try {
173             rwTx.delete(LogicalDatastoreType.CONFIGURATION, iid);
174             final CheckedFuture<Void, TransactionCommitFailedException> futureTask = rwTx.submit();
175             futureTask.get();
176             LOG.trace("Netconf DELETE transaction done for {}", iid);
177             return true;
178         } catch (Exception e) {
179             // Retry
180             if (retryCounter > 0) {
181                 LOG.warn("Netconf DELETE transaction failed to {}. Restarting transaction ... ", e.getMessage());
182                 return deleteIfExists(mountpoint, iid, --retryCounter);
183             } else {
184                 LOG.warn("Netconf DELETE transaction unsuccessful. Maximal number of attempts reached. Trace: {}", e);
185                 return false;
186             }
187         }
188     }
189 }