OVSDB-432: Add method to restart OVSDB server and limit retry times and timeout 90/63890/6
authorHsin-Yi Shen <syshen66@gmail.com>
Mon, 25 Sep 2017 21:53:47 +0000 (17:53 -0400)
committerAnil Vishnoi <vishnoianil@gmail.com>
Tue, 31 Oct 2017 00:27:32 +0000 (00:27 +0000)
This patch makes following changes:
1. Add restart method to restart OVSDB server. User wiil be able
   to restart OVSDB server with different sets of SSL protocol
   and cipher suites.
2. Limit retry times for certain SSL handshake status. In current
   code, it retry infinite times for some SSL handshake status
   and cause issue. This patch will fix it.
3. Add API in OvsdbClient interface to provide custom timeout value for
   monitor and cancel monitor transactions. This avoids
   blocking thread due to unsuccessful transaction.
4. Fix typo in Function.java

Change-Id: I4f07e2f32889099e65a06a3afc4a263714dd5946
Signed-off-by: Hsin-Yi Shen <syshen66@gmail.com>
library/impl/src/main/java/org/opendaylight/ovsdb/lib/OvsdbClient.java
library/impl/src/main/java/org/opendaylight/ovsdb/lib/OvsdbConnection.java
library/impl/src/main/java/org/opendaylight/ovsdb/lib/impl/OvsdbClientImpl.java
library/impl/src/main/java/org/opendaylight/ovsdb/lib/impl/OvsdbConnectionService.java
library/impl/src/main/java/org/opendaylight/ovsdb/lib/jsonrpc/JsonRpcEndpoint.java
library/impl/src/main/java/org/opendaylight/ovsdb/lib/notation/Function.java

index 817a0caaad3b25958587f81a556c5eef4e94c864..6c53193cab4e8d7a02244b0a8a7e514853629f19 100644 (file)
@@ -65,6 +65,18 @@ public interface OvsdbClient {
                                                     List<MonitorRequest> monitorRequests,
                                                     MonitorCallBack callback);
 
+    /**
+     * ovsdb <a href="http://tools.ietf.org/html/draft-pfaff-ovsdb-proto-04#section-4.1.5">monitor</a> operation.
+     * @param monitorRequests represents what needs to be monitored including a client specified monitor handle. This
+     *                       handle is used to later cancel ({@link #cancelMonitor(MonitorHandle)}) the monitor.
+     * @param callback receives the monitor response
+     * @param timeout time in seconds for monitor transaction timeout
+     */
+    <E extends TableSchema<E>> TableUpdates monitor(DatabaseSchema schema,
+                                                    List<MonitorRequest> monitorRequests,
+                                                    MonitorCallBack callback,
+                                                    int timeout);
+
     /**
      * ovsdb <a href="http://tools.ietf.org/html/draft-pfaff-ovsdb-proto-04#section-4.1.5">monitor</a> operation.
      * @param monitorRequests represents what needs to be monitored
@@ -77,6 +89,20 @@ public interface OvsdbClient {
                                                     MonitorHandle monitorHandle,
                                                     MonitorCallBack callback);
 
+    /**
+     * ovsdb <a href="http://tools.ietf.org/html/draft-pfaff-ovsdb-proto-04#section-4.1.5">monitor</a> operation.
+     * @param monitorRequests represents what needs to be monitored
+     * @param monitorHandle  A client specified monitor handle. This handle is used to later cancel
+     *                       ({@link #cancelMonitor(MonitorHandle)}) the monitor.
+     * @param callback receives the monitor response
+     * @param timeout time in seconds for monitor transaction timeout
+     */
+    <E extends TableSchema<E>> TableUpdates monitor(DatabaseSchema schema,
+                                                    List<MonitorRequest> monitorRequests,
+                                                    MonitorHandle monitorHandle,
+                                                    MonitorCallBack callback,
+                                                    int timeout);
+
     /**
      * Cancels an existing monitor method.
      * @param handler Handle identifying a specific monitor request that is being cancelled.
@@ -84,6 +110,14 @@ public interface OvsdbClient {
      */
     void cancelMonitor(MonitorHandle handler);
 
+    /**
+     * Cancels an existing monitor method.
+     * @param handler Handle identifying a specific monitor request that is being cancelled.
+     * @param timeout time in seconds for monitor transaction timeout
+     * @throws java.lang.IllegalStateException if there is no outstanding monitor request for this handle
+     */
+    void cancelMonitor(MonitorHandle handler, int timeout);
+
     /**
      * ovsdb <a href="http://tools.ietf.org/html/draft-pfaff-ovsdb-proto-04#section-4.1.8">lock</a> operation.
      * @param lockId a client specified id for the lock; this can be used for unlocking ({@link #unLock(String)})
index 9ea618a5f8c8eb89462ebc0d6503543ca900dea3..2ad61db9740a01ebd5066d79016341c57fc76140 100644 (file)
@@ -62,6 +62,15 @@ public interface OvsdbConnection {
     boolean startOvsdbManagerWithSsl(int ovsdbListenPort,
                                      SSLContext sslContext, String[] protocols, String[] cipherSuites);
 
+    /**
+     * Method to restart ovsdb server for passive connection with SSL and user
+     * specifies protocols and cipher suites.
+     */
+    boolean restartOvsdbManagerWithSsl(int ovsdbListenPort,
+        SSLContext sslContext,
+        String[] protocols,
+        String[] cipherSuites);
+
     /**
      * Method to register a Passive Connection Listener with the ConnectionService.
      * @param listener Passive Connection listener interested in Passive OVSDB connection requests.
index 290b0fe70d3d3c9a5d6f8a0a5e5d3bcc1db129c5..0b5e045a30a4ba60eb559d86753cc12d4c7c32d3 100644 (file)
@@ -29,6 +29,8 @@ import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 import org.opendaylight.ovsdb.lib.EchoServiceCallbackFilters;
 import org.opendaylight.ovsdb.lib.LockAquisitionCallback;
 import org.opendaylight.ovsdb.lib.LockStolenCallback;
@@ -70,6 +72,7 @@ public class OvsdbClientImpl implements OvsdbClient {
     private OvsdbConnectionInfo connectionInfo;
     private Channel channel;
     private boolean isConnectionPublished;
+    private static final int NO_TIMEOUT = -1;
 
     private static final ThreadFactory THREAD_FACTORY_SSL =
         new ThreadFactoryBuilder().setNameFormat("OVSDB-PassiveConnection-SSL-%d").build();
@@ -181,10 +184,18 @@ public class OvsdbClientImpl implements OvsdbClient {
         return FutureTransformUtils.transformTransactResponse(rpc.transact(builder), operations);
     }
 
+    @Override
+    public <E extends TableSchema<E>> TableUpdates monitor(final DatabaseSchema dbSchema,
+                                                           List<MonitorRequest> monitorRequest,
+                                                           final MonitorCallBack callback) {
+        return monitor(dbSchema, monitorRequest, callback, NO_TIMEOUT);
+    }
+
     @Override
     public <E extends TableSchema<E>> TableUpdates monitor(final DatabaseSchema dbSchema,
                                                             List<MonitorRequest> monitorRequest,
-                                                            final MonitorCallBack callback) {
+                                                            final MonitorCallBack callback,
+                                                            int timeout) {
 
         final ImmutableMap<String, MonitorRequest> reqMap = Maps.uniqueIndex(monitorRequest,
                 MonitorRequest::getTableName);
@@ -196,8 +207,12 @@ public class OvsdbClientImpl implements OvsdbClient {
             () -> Arrays.asList(dbSchema.getName(), monitorHandle.getId(), reqMap));
         JsonNode result;
         try {
-            result = monitor.get();
-        } catch (InterruptedException | ExecutionException e) {
+            if (timeout == NO_TIMEOUT) {
+                result = monitor.get();
+            } else {
+                result = monitor.get(timeout, TimeUnit.SECONDS);
+            }
+        } catch (InterruptedException | ExecutionException | TimeoutException e) {
             LOG.warn("Failed to monitor {}", dbSchema, e);
             return null;
         }
@@ -209,6 +224,15 @@ public class OvsdbClientImpl implements OvsdbClient {
                                                            List<MonitorRequest> monitorRequest,
                                                            final MonitorHandle monitorHandle,
                                                            final MonitorCallBack callback) {
+        return monitor(dbSchema, monitorRequest, monitorHandle, callback, NO_TIMEOUT);
+    }
+
+    @Override
+    public <E extends TableSchema<E>> TableUpdates monitor(final DatabaseSchema dbSchema,
+                                                           List<MonitorRequest> monitorRequest,
+                                                           final MonitorHandle monitorHandle,
+                                                           final MonitorCallBack callback,
+                                                           int timeout) {
 
         final ImmutableMap<String, MonitorRequest> reqMap = Maps.uniqueIndex(monitorRequest,
                 MonitorRequest::getTableName);
@@ -219,8 +243,12 @@ public class OvsdbClientImpl implements OvsdbClient {
             () -> Arrays.asList(dbSchema.getName(), monitorHandle.getId(), reqMap));
         JsonNode result;
         try {
-            result = monitor.get();
-        } catch (InterruptedException | ExecutionException e) {
+            if (timeout == NO_TIMEOUT) {
+                result = monitor.get();
+            } else {
+                result = monitor.get(timeout, TimeUnit.SECONDS);
+            }
+        } catch (InterruptedException | ExecutionException | TimeoutException e) {
             LOG.warn("Failed to monitor {}", dbSchema, e);
             return null;
         }
@@ -234,12 +262,21 @@ public class OvsdbClientImpl implements OvsdbClient {
 
     @Override
     public void cancelMonitor(final MonitorHandle handler) {
+        cancelMonitor(handler, NO_TIMEOUT);
+    }
+
+    @Override
+    public void cancelMonitor(final MonitorHandle handler, int timeout) {
         ListenableFuture<JsonNode> cancelMonitor = rpc.monitor_cancel(() -> Collections.singletonList(handler.getId()));
 
         JsonNode result = null;
         try {
-            result = cancelMonitor.get();
-        } catch (InterruptedException | ExecutionException e) {
+            if (timeout == NO_TIMEOUT) {
+                result = cancelMonitor.get();
+            } else {
+                result = cancelMonitor.get(timeout, TimeUnit.SECONDS);
+            }
+        } catch (InterruptedException | ExecutionException | TimeoutException e) {
             LOG.error("Exception when canceling monitor handler {}", handler.getId(), e);
         }
 
index 79152a716c1981b7c26580db32b14544c856e3fa..66bbd150b688a41f58ab08de49b74b954c81a8a9 100644 (file)
@@ -86,7 +86,6 @@ import org.slf4j.LoggerFactory;
  */
 public class OvsdbConnectionService implements AutoCloseable, OvsdbConnection {
     private static final Logger LOG = LoggerFactory.getLogger(OvsdbConnectionService.class);
-
     private static ThreadFactory passiveConnectionThreadFactory = new ThreadFactoryBuilder()
             .setNameFormat("OVSDBPassiveConnServ-%d").build();
     private static ScheduledExecutorService executorService
@@ -113,6 +112,7 @@ public class OvsdbConnectionService implements AutoCloseable, OvsdbConnection {
 
     private static final StalePassiveConnectionService STALE_PASSIVE_CONNECTION_SERVICE =
             new StalePassiveConnectionService(executorService);
+    private static Channel serverChannel = null;
 
     private static int retryPeriod = 100; // retry after 100 milliseconds
 
@@ -269,6 +269,19 @@ public class OvsdbConnectionService implements AutoCloseable, OvsdbConnection {
         }
     }
 
+    @Override
+    public synchronized boolean restartOvsdbManagerWithSsl(final int ovsdbListenPort,
+        final SSLContext sslContext,
+        final String[] protocols,
+        final String[] cipherSuites) {
+        if (singletonCreated.getAndSet(false) && (serverChannel != null)) {
+            serverChannel.close();
+            LOG.info("Server channel closed");
+        }
+        serverChannel = null;
+        return startOvsdbManagerWithSsl(ovsdbListenPort, sslContext, protocols, cipherSuites);
+    }
+
     /**
      * OVSDB Passive listening thread that uses Netty ServerBootstrap to open
      * passive connection handle channel callbacks.
@@ -344,6 +357,7 @@ public class OvsdbConnectionService implements AutoCloseable, OvsdbConnection {
             // Start the server.
             ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
             Channel serverListenChannel = channelFuture.channel();
+            serverChannel = serverListenChannel;
             // Wait until the server socket is closed.
             serverListenChannel.closeFuture().sync();
         } catch (InterruptedException e) {
@@ -396,6 +410,16 @@ public class OvsdbConnectionService implements AutoCloseable, OvsdbConnection {
                     this.retryTimes = 3;
                 }
 
+                private void retry() {
+                    if (retryTimes > 0) {
+                        executorService.schedule(this,  retryPeriod, TimeUnit.MILLISECONDS);
+                    } else {
+                        LOG.debug("channel closed {}", channel);
+                        channel.disconnect();
+                    }
+                    retryTimes--;
+                }
+
                 @Override
                 public void run() {
                     HandshakeStatus status = sslHandler.engine().getHandshakeStatus();
@@ -407,7 +431,7 @@ public class OvsdbConnectionService implements AutoCloseable, OvsdbConnection {
                                     .equals("SSL_NULL_WITH_NULL_NULL")) {
                                 // Not begin handshake yet. Retry later.
                                 LOG.debug("handshake not begin yet {}", status);
-                                executorService.schedule(this, retryPeriod, TimeUnit.MILLISECONDS);
+                                retry();
                             } else {
                               //Check if peer is trusted before notifying listeners
                                 try {
@@ -419,7 +443,7 @@ public class OvsdbConnectionService implements AutoCloseable, OvsdbConnection {
                                 } catch (SSLPeerUnverifiedException e) {
                                     //Trust manager is still checking peer certificate. Retry later
                                     LOG.debug("Peer certifiacte is not verified yet {}", status);
-                                    executorService.schedule(this, retryPeriod, TimeUnit.MILLISECONDS);
+                                    retry();
                                 }
                             }
                             break;
@@ -428,7 +452,7 @@ public class OvsdbConnectionService implements AutoCloseable, OvsdbConnection {
                         case NEED_TASK:
                             //Handshake still ongoing. Retry later.
                             LOG.debug("handshake not done yet {}", status);
-                            executorService.schedule(this,  retryPeriod, TimeUnit.MILLISECONDS);
+                            retry();
                             break;
 
                         case NEED_WRAP:
@@ -436,6 +460,7 @@ public class OvsdbConnectionService implements AutoCloseable, OvsdbConnection {
                                     .equals("SSL_NULL_WITH_NULL_NULL")) {
                                 /* peer not authenticated. No need to notify listener in this case. */
                                 LOG.error("Ssl handshake fail. channel {}", channel);
+                                channel.disconnect();
                             } else {
                                 /*
                                  * peer is authenticated. Give some time to wait for completion.
@@ -447,12 +472,7 @@ public class OvsdbConnectionService implements AutoCloseable, OvsdbConnection {
                                  * since client will reconnect later.
                                  */
                                 LOG.debug("handshake not done yet {}", status);
-                                if (retryTimes > 0) {
-                                    executorService.schedule(this,  retryPeriod, TimeUnit.MILLISECONDS);
-                                } else {
-                                    LOG.debug("channel closed {}", channel);
-                                }
-                                retryTimes--;
+                                retry();
                             }
                             break;
 
index 4a71897d62444699da23a7d6ead4d39dd4a1b3de..5d0e57c6f7634ad1695760e8e0ec7cc5d07a88bb 100644 (file)
@@ -27,6 +27,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ThreadFactory;
@@ -76,7 +77,7 @@ public class JsonRpcEndpoint {
 
     ObjectMapper objectMapper;
     Channel nettyChannel;
-    Map<String, CallContext> methodContext = new HashMap<>();
+    Map<String, CallContext> methodContext = new ConcurrentHashMap<>();
     Map<Object, OvsdbRPC.Callback> requestCallbacks = new HashMap<>();
 
     public JsonRpcEndpoint(ObjectMapper objectMapper, Channel channel) {
index d106dee718fe3d39772a02d237352baba612d577..a99b121d6e7de14b91b0d06e842f2f41d03a3df5 100644 (file)
@@ -13,7 +13,7 @@ public enum Function {
     LESS_THAN_OR_EQUALS("<="),
     EQUALS("=="),
     NOT_EQUALS("!="),
-    GREATER_THAN(">="),
+    GREATER_THAN(">"),
     GREATER_THAN_OR_EQUALS(">="),
     INCLUDES("includes"),
     EXCLUDES("excludes");