Bug 6465 Controller goes into slave mode 46/44146/7
authorJozef Bacigal <jozef.bacigal@pantheon.tech>
Wed, 17 Aug 2016 11:52:50 +0000 (13:52 +0200)
committerJozef Bacigal <jozef.bacigal@pantheon.tech>
Fri, 19 Aug 2016 09:55:13 +0000 (11:55 +0200)
- Changed lifecycle service in order to
create lazy initilization of context in cluster
- Removed clustering initialization per context
- Changed reconnect strategy if not in disconnecting state
- Some performance improvements
- Removed OFManager general API

Change-Id: I37e8f99a0590633a3e5c179b092c6b1c65e9cb1d
Signed-off-by: Jozef Bacigal <jozef.bacigal@pantheon.tech>
21 files changed:
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/OFPContext.java
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/OFPManager.java [deleted file]
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/DeviceManager.java
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/handlers/ClusterInitializationPhaseHandler.java [new file with mode: 0644]
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/handlers/ClusterLifecycleSupervisor.java [new file with mode: 0644]
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/lifecycle/LifecycleService.java
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/role/RoleManager.java
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/rpc/RpcManager.java
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/statistics/StatisticsContext.java
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/statistics/StatisticsManager.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/connection/listener/HandshakeListenerImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceContextImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceManagerImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/lifecycle/LifecycleServiceImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/role/RoleContextImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/role/RoleManagerImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/rpc/RpcContextImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/rpc/RpcManagerImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/StatisticsContextImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/StatisticsManagerImpl.java
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/lifecycle/LifecycleServiceImplTest.java

index c16d5fafb6b16fd97d6f0a728d473f7332ce4ba0..fad140245183c3a4e79fe7a3e1ab54c5e11f5301 100644 (file)
@@ -9,15 +9,16 @@ package org.opendaylight.openflowplugin.api.openflow;
 
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
-import java.util.concurrent.ExecutionException;
 import java.util.concurrent.RejectedExecutionException;
 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
+import org.opendaylight.openflowplugin.api.openflow.device.handlers.ClusterInitializationPhaseHandler;
+import org.opendaylight.openflowplugin.api.openflow.device.handlers.ClusterLifecycleSupervisor;
 
 /**
  * General API for all OFP Context
  */
-public interface OFPContext {
+public interface OFPContext extends ClusterLifecycleSupervisor, ClusterInitializationPhaseHandler {
 
     void setState(CONTEXT_STATE contextState);
 
@@ -38,17 +39,10 @@ public interface OFPContext {
      */
     CONTEXT_STATE getState();
 
-    /**
-     * Starting cluster services for context becoming master
-     */
-    default void startupClusterServices() throws ExecutionException, InterruptedException {
-        throw new InterruptedException("Cannot start abstract service, check implementation of cluster services");
-    }
-
     /**
      * About to stop services in cluster not master anymore or going down
      * @return Future most of services need time to be closed
-     * @param deviceDisconnected
+     * @param deviceDisconnected true if clustering services stopping by device disconnect
      */
     default ListenableFuture<Void> stopClusterServices(final boolean deviceDisconnected){
         return Futures.immediateFailedFuture(new RejectedExecutionException("Cannot stop abstract services, check implementation of cluster services"));
diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/OFPManager.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/OFPManager.java
deleted file mode 100644 (file)
index 1879a4c..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.openflowplugin.api.openflow;
-
-import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
-
-/**
- * Generic API for all managers
- */
-public interface OFPManager {
-
-    <T extends OFPContext> T gainContext(final DeviceInfo deviceInfo);
-
-}
index d965bd94d427fb74d644f6f8426d2c583057a3c1..d93fc9b7b44b5efbd2082f12a78e1281ac5e9881 100644 (file)
@@ -8,13 +8,11 @@
 
 package org.opendaylight.openflowplugin.api.openflow.device;
 
-import org.opendaylight.openflowplugin.api.openflow.OFPManager;
 import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceConnectedHandler;
 import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceDisconnectedHandler;
 import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceInitializationPhaseHandler;
 import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceLifecycleSupervisor;
 import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceTerminationPhaseHandler;
-import org.opendaylight.openflowplugin.api.openflow.lifecycle.LifecycleService;
 import org.opendaylight.openflowplugin.api.openflow.translator.TranslatorLibrarian;
 
 /**
@@ -23,7 +21,7 @@ import org.opendaylight.openflowplugin.api.openflow.translator.TranslatorLibrari
  * has its own device context managed by this manager.
  */
 public interface DeviceManager extends DeviceConnectedHandler, DeviceDisconnectedHandler, DeviceLifecycleSupervisor,
-        DeviceInitializationPhaseHandler, DeviceTerminationPhaseHandler, TranslatorLibrarian, AutoCloseable, OFPManager {
+        DeviceInitializationPhaseHandler, DeviceTerminationPhaseHandler, TranslatorLibrarian, AutoCloseable {
 
 
     /**
diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/handlers/ClusterInitializationPhaseHandler.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/handlers/ClusterInitializationPhaseHandler.java
new file mode 100644 (file)
index 0000000..497bb29
--- /dev/null
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2016 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.openflowplugin.api.openflow.device.handlers;
+
+import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
+
+/**
+ * Interface handles MASTER initialization on ownership change
+ */
+public interface ClusterInitializationPhaseHandler {
+
+    /**
+     * Method for initialization cycle between contexts
+     * @param connectionContext to check actual connection state
+     */
+    boolean onContextInstantiateService(final ConnectionContext connectionContext);
+
+    /**
+     * Method for initial submit transaction after successful initial gathering
+     */
+    default void initialSubmitTransaction(){
+        //This method need to be override only in device context to submit initial data
+    }
+}
diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/handlers/ClusterLifecycleSupervisor.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/handlers/ClusterLifecycleSupervisor.java
new file mode 100644 (file)
index 0000000..6655daf
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2016 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.api.openflow.device.handlers;
+
+/**
+ * Interface has to implement all relevant manager to correctly handling
+ * device context initialization when device MASTER. Methods are used for order
+ * handlers in initialization phase. Ordering is easily changed
+ * pragmatically by definition.
+ */
+public interface ClusterLifecycleSupervisor {
+
+    /**
+     * Method sets relevant {@link ClusterInitializationPhaseHandler} for building
+     * handler's chain for Device mastership phase.
+     * @param handler handler
+     */
+    void setLifecycleInitializationPhaseHandler(final ClusterInitializationPhaseHandler handler);
+
+    default void setInitialSubmitHandler(final ClusterInitializationPhaseHandler initialSubmitHandler) {
+        //Need to be only set in statistics context where after successful initial gather
+        //tx need to be submitted
+    }
+
+}
index 0eca3b7d15260ef40ba678767982005c4e8ca5db..3084568e3c687cd6d3395b7553afd9fe8e0eafd5 100644 (file)
@@ -11,6 +11,8 @@ package org.opendaylight.openflowplugin.api.openflow.lifecycle;
 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
+import org.opendaylight.openflowplugin.api.openflow.device.handlers.ClusterInitializationPhaseHandler;
+import org.opendaylight.openflowplugin.api.openflow.device.handlers.ClusterLifecycleSupervisor;
 import org.opendaylight.openflowplugin.api.openflow.role.RoleContext;
 import org.opendaylight.openflowplugin.api.openflow.rpc.RpcContext;
 import org.opendaylight.openflowplugin.api.openflow.statistics.StatisticsContext;
@@ -18,7 +20,7 @@ import org.opendaylight.openflowplugin.api.openflow.statistics.StatisticsContext
 /**
  * Service for starting or stopping all services in plugin in cluster
  */
-public interface LifecycleService extends ClusterSingletonService, AutoCloseable {
+public interface LifecycleService extends ClusterSingletonService, AutoCloseable, ClusterLifecycleSupervisor, ClusterInitializationPhaseHandler {
 
     /**
      * This method registers lifecycle service to the given provider
index e14631a414a69f3cea9e3c0b71fdfda5f3749cfc..2b99fc99d6ebb19beaee2348f3b3263a55c582cc 100644 (file)
@@ -9,7 +9,6 @@ package org.opendaylight.openflowplugin.api.openflow.role;
 
 import com.google.common.util.concurrent.CheckedFuture;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
-import org.opendaylight.openflowplugin.api.openflow.OFPManager;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
 import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceInitializationPhaseHandler;
 import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceLifecycleSupervisor;
@@ -22,8 +21,7 @@ public interface RoleManager extends
         DeviceLifecycleSupervisor,
         DeviceInitializationPhaseHandler,
         AutoCloseable,
-        DeviceTerminationPhaseHandler,
-        OFPManager {
+        DeviceTerminationPhaseHandler {
 
     CheckedFuture<Void, TransactionCommitFailedException> removeDeviceFromOperationalDS(final DeviceInfo deviceInfo, final int numRetries);
 }
index 25eedcbac1150bef2e5e9bfabeb7c83145d09805..eae6757584de402de13a1ff2a346d499ad923349 100644 (file)
@@ -8,7 +8,6 @@
 
 package org.opendaylight.openflowplugin.api.openflow.rpc;
 
-import org.opendaylight.openflowplugin.api.openflow.OFPManager;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
 import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceInitializationPhaseHandler;
 import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceLifecycleSupervisor;
@@ -18,10 +17,8 @@ import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceTermin
  * The RPC Manager will maintain an RPC Context for each online switch. RPC context for device is created when
  * {@link DeviceInitializationPhaseHandler#onDeviceContextLevelUp(DeviceInfo, org.opendaylight.openflowplugin.api.openflow.lifecycle.LifecycleService)}
  * is called.
- * <p>
- * Created by Martin Bobak &lt;mbobak@cisco.com&gt; on 25.2.2015.
  */
-public interface RpcManager extends DeviceLifecycleSupervisor, DeviceInitializationPhaseHandler, AutoCloseable, DeviceTerminationPhaseHandler, OFPManager {
+public interface RpcManager extends DeviceLifecycleSupervisor, DeviceInitializationPhaseHandler, AutoCloseable, DeviceTerminationPhaseHandler {
 
     void setStatisticsRpcEnabled(boolean statisticsRpcEnabled);
 }
index 0fbc6905d7d766afd00ba85fcbb633245a6ef487..96df0e1455e012199d699cd96b53d1687984c50d 100644 (file)
@@ -12,8 +12,6 @@ import com.google.common.util.concurrent.ListenableFuture;
 import io.netty.util.Timeout;
 import java.util.Optional;
 import org.opendaylight.openflowplugin.api.openflow.OFPContext;
-import org.opendaylight.openflowplugin.api.openflow.OFPManager;
-import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
 import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
 import org.opendaylight.openflowplugin.api.openflow.lifecycle.LifecycleService;
 import org.opendaylight.openflowplugin.api.openflow.rpc.listener.ItemLifecycleListener;
index 8a8561db76a0f29c174b20f6c7a90175e5268ef5..c56e50ca252ac9156f384af236252f2053dad8ba 100644 (file)
@@ -8,7 +8,6 @@
 
 package org.opendaylight.openflowplugin.api.openflow.statistics;
 
-import org.opendaylight.openflowplugin.api.openflow.OFPManager;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
 import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceInitializationPhaseHandler;
 import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceLifecycleSupervisor;
@@ -18,7 +17,7 @@ import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceTermin
  * Manager to start or stop scheduling statistics
  */
 public interface StatisticsManager extends DeviceLifecycleSupervisor, DeviceInitializationPhaseHandler,
-        DeviceTerminationPhaseHandler, AutoCloseable, OFPManager {
+        DeviceTerminationPhaseHandler, AutoCloseable {
 
     /**
      * Start scheduling statistic gathering for given device info
index d1de6f8a20305ada3620e476394c9e08e186990d..82ad28a2b15d547d103f744de9ee1706117bb03b 100644 (file)
@@ -69,8 +69,8 @@ public class HandshakeListenerImpl implements HandshakeListener {
                 LOG.debug("succeeded by getting sweep barrier after post-handshake for device {}", connectionContext.getNodeId().getValue());
                 try {
                     ConnectionStatus connectionStatusResult = deviceConnectedHandler.deviceConnected(connectionContext);
-                    if (ConnectionStatus.CLOSING.equals(connectionStatusResult)) {
-                        connectionContext.closeConnection(false);
+                    if (!ConnectionStatus.MAY_CONTINUE.equals(connectionStatusResult)) {
+                        connectionContext.closeConnection(ConnectionStatus.ALREADY_CONNECTED.equals(connectionStatusResult));
                     }
                     SessionStatistics.countEvent(connectionContext.getNodeId().toString(),
                             SessionStatistics.ConnectionStatus.CONNECTION_CREATED);
index 6b53858e870a6f4d5e7b80441b82a704fab2ebe7..032f86c867b9cefd18d871878134884f710d0245 100644 (file)
@@ -37,6 +37,7 @@ import org.opendaylight.openflowplugin.api.openflow.device.MessageTranslator;
 import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
 import org.opendaylight.openflowplugin.api.openflow.device.TranslatorLibrary;
 import org.opendaylight.openflowplugin.api.openflow.device.Xid;
+import org.opendaylight.openflowplugin.api.openflow.device.handlers.ClusterInitializationPhaseHandler;
 import org.opendaylight.openflowplugin.api.openflow.device.handlers.MultiMsgCollector;
 import org.opendaylight.openflowplugin.api.openflow.lifecycle.LifecycleService;
 import org.opendaylight.openflowplugin.api.openflow.md.core.SwitchConnectionDistinguisher;
@@ -137,6 +138,7 @@ public class DeviceContextImpl implements DeviceContext, ExtensionConverterProvi
     private final DeviceInfo deviceInfo;
     private final ConvertorExecutor convertorExecutor;
     private volatile CONTEXT_STATE state;
+    private ClusterInitializationPhaseHandler clusterInitializationPhaseHandler;
 
     public DeviceContextImpl(
             @Nonnull final ConnectionContext primaryConnectionContext,
@@ -538,14 +540,6 @@ public class DeviceContextImpl implements DeviceContext, ExtensionConverterProvi
         this.state = state;
     }
 
-    @Override
-    public void startupClusterServices() throws ExecutionException, InterruptedException {
-        LOG.debug("Initializing transaction chain manager for node {}", getDeviceInfo().getLOGValue());
-        this.transactionChainManager.activateTransactionManager();
-        LOG.debug("Waiting to get node {} information", getDeviceInfo().getLOGValue());
-        DeviceInitializationUtils.initializeNodeInformation(this, switchFeaturesMandatory, this.convertorExecutor);
-    }
-
     @Override
     public ListenableFuture<Void> stopClusterServices(boolean deviceDisconnected) {
         return this.transactionChainManager.deactivateTransactionManager();
@@ -578,4 +572,31 @@ public class DeviceContextImpl implements DeviceContext, ExtensionConverterProvi
     public boolean isSkipTableFeatures() {
         return this.skipTableFeatures;
     }
+
+    @Override
+    public void setLifecycleInitializationPhaseHandler(final ClusterInitializationPhaseHandler handler) {
+        this.clusterInitializationPhaseHandler = handler;
+    }
+
+    @Override
+    public boolean onContextInstantiateService(final ConnectionContext connectionContext) {
+
+        if (getPrimaryConnectionContext().getConnectionState().equals(ConnectionContext.CONNECTION_STATE.RIP)) {
+            LOG.warn("Connection on device {} was interrupted, will stop starting master services.", deviceInfo.getLOGValue());
+            return false;
+        }
+
+        LOG.info("Starting device context cluster services for node {}", deviceInfo.getLOGValue());
+
+        this.transactionChainManager.activateTransactionManager();
+
+        try {
+            DeviceInitializationUtils.initializeNodeInformation(this, switchFeaturesMandatory, this.convertorExecutor);
+        } catch (ExecutionException | InterruptedException e) {
+            LOG.warn("Device {} cannot be initialized: ", deviceInfo.getLOGValue(), e);
+            return false;
+        }
+
+        return this.clusterInitializationPhaseHandler.onContextInstantiateService(getPrimaryConnectionContext());
+    }
 }
index aae6b2f15b3d0ee79f1e837feab4247c84b53fe4..31795d68e1abe9f158217e9aedf9b14a849e625b 100644 (file)
@@ -158,14 +158,12 @@ public class DeviceManagerImpl implements DeviceManager, ExtensionConverterProvi
          */
          if (deviceContexts.containsKey(deviceInfo)) {
              DeviceContext deviceContext = deviceContexts.get(deviceInfo);
+             LOG.warn("Node {} already connected disconnecting device. Rejecting connection", deviceInfo);
              if (!deviceContext.getState().equals(OFPContext.CONTEXT_STATE.TERMINATION)) {
-                 LOG.info("Node {} already connected but context state not in TERMINATION state, replacing connection context",
+                 LOG.warn("Node {} context state not in TERMINATION state.",
                          connectionContext.getDeviceInfo().getLOGValue());
-                 deviceContext.replaceConnectionContext(connectionContext);
                  return ConnectionStatus.ALREADY_CONNECTED;
              } else {
-                 LOG.warn("Rejecting connection from node which is already connected and there exist deviceContext for it: {}",
-                         connectionContext.getDeviceInfo().getLOGValue());
                  return ConnectionStatus.CLOSING;
              }
          }
@@ -364,11 +362,6 @@ public class DeviceManagerImpl implements DeviceManager, ExtensionConverterProvi
         deviceContexts.put(deviceInfo, deviceContext);
     }
 
-    @Override
-    public <T extends OFPContext> T gainContext(final DeviceInfo deviceInfo) {
-        return (T) deviceContexts.get(deviceInfo);
-    }
-
     @Override
     public void setIsNotificationFlowRemovedOff(boolean isNotificationFlowRemovedOff) {
         this.isNotificationFlowRemovedOff = isNotificationFlowRemovedOff;
index 729a3d8718defb60a2a01985ed0e8c3da2766b9a..6e201b9dc6dbab371c993a9b2773925cabea3094 100644 (file)
@@ -1,5 +1,5 @@
-/*
- * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+/**
+ * Copyright (c) 2016 Pantheon Technologies s.r.o. and others. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -14,13 +14,13 @@ import com.google.common.util.concurrent.ListenableFuture;
 import java.util.Collection;
 import java.util.List;
 import java.util.Objects;
-import java.util.concurrent.ExecutionException;
 import javax.annotation.Nullable;
 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
+import org.opendaylight.openflowplugin.api.openflow.device.handlers.ClusterInitializationPhaseHandler;
 import org.opendaylight.openflowplugin.api.openflow.lifecycle.LifecycleService;
 import org.opendaylight.openflowplugin.api.openflow.role.RoleContext;
 import org.opendaylight.openflowplugin.api.openflow.rpc.RpcContext;
@@ -38,70 +38,21 @@ public class LifecycleServiceImpl implements LifecycleService {
     private RoleContext roleContext;
     private StatisticsContext statContext;
     private ClusterSingletonServiceRegistration registration;
+    private ClusterInitializationPhaseHandler clusterInitializationPhaseHandler;
 
 
     @Override
     public void instantiateServiceInstance() {
-        try {
 
-            if (LOG.isDebugEnabled()) {
-                LOG.debug("========== Starting clustering MASTER services for node {} ==========", this.deviceContext.getDeviceInfo().getLOGValue());
-            }
-
-            if (connectionInterrupted()) {
-                return;
-            }
-
-            LOG.info("Starting device context cluster services for node {}", getIdentifier());
-            this.deviceContext.startupClusterServices();
-
-            if (connectionInterrupted()) {
-                return;
-            }
-
-            LOG.info("Starting statistics context cluster services for node {}", getIdentifier());
-            this.statContext.startupClusterServices();
-
-            if (connectionInterrupted()) {
-                return;
-            }
-
-            LOG.info("Statistics initial gathering OK, submitting data for node {}", getIdentifier());
-            this.deviceContext.initialSubmitTransaction();
-
-            if (connectionInterrupted()) {
-                return;
-            }
-
-            LOG.info("Starting rpc context cluster services for node {}", getIdentifier());
-            this.rpcContext.startupClusterServices();
-
-            if (connectionInterrupted()) {
-                return;
-            }
+        LOG.info("========== Starting clustering MASTER services for node {} ==========", this.deviceContext.getDeviceInfo().getLOGValue());
 
-            LOG.info("Starting role context cluster services for node {}", getIdentifier());
-            this.roleContext.startupClusterServices();
-
-            if (connectionInterrupted()) {
-                return;
-            }
-
-            LOG.info("Caching flows IDs ...");
-            fillDeviceFlowRegistry();
-
-        } catch (ExecutionException | InterruptedException e) {
-            LOG.warn("Cluster service {} was unable to start.", this.getIdentifier());
-            this.deviceContext.shutdownConnection();
+        if (this.clusterInitializationPhaseHandler.onContextInstantiateService(null)) {
+            LOG.info("========== Start-up clustering MASTER services for node {} was SUCCESSFUL ==========", this.deviceContext.getDeviceInfo().getLOGValue());
+        } else {
+            LOG.warn("========== Start-up clustering MASTER services for node {} was UN-SUCCESSFUL ==========", this.deviceContext.getDeviceInfo().getLOGValue());
+            this.closeConnection();
         }
-    }
 
-    private boolean connectionInterrupted() {
-        if (this.deviceContext.getPrimaryConnectionContext().getConnectionState().equals(ConnectionContext.CONNECTION_STATE.RIP)) {
-            LOG.warn("Node {} was disconnected, will stop starting MASTER services.", this.deviceContext.getDeviceInfo().getLOGValue());
-            return true;
-        }
-        return false;
     }
 
     @Override
@@ -145,6 +96,15 @@ public class LifecycleServiceImpl implements LifecycleService {
 
     @Override
     public void registerService(final ClusterSingletonServiceProvider singletonServiceProvider) {
+        //lifecycle service -> device context -> statistics context -> rpc context -> role context -> lifecycle service
+        this.clusterInitializationPhaseHandler = deviceContext;
+        this.deviceContext.setLifecycleInitializationPhaseHandler(this.statContext);
+        this.statContext.setLifecycleInitializationPhaseHandler(this.rpcContext);
+        this.rpcContext.setLifecycleInitializationPhaseHandler(this.roleContext);
+        this.roleContext.setLifecycleInitializationPhaseHandler(this);
+        //Set initial submit handler
+        this.statContext.setInitialSubmitHandler(this.deviceContext);
+        //Register cluster singleton service
         this.registration = singletonServiceProvider.registerClusterSingletonService(this);
     }
 
@@ -218,4 +178,23 @@ public class LifecycleServiceImpl implements LifecycleService {
         });
     }
 
+    @Override
+    public void setLifecycleInitializationPhaseHandler(final ClusterInitializationPhaseHandler handler) {
+        this.clusterInitializationPhaseHandler = handler;
+    }
+
+    @Override
+    public boolean onContextInstantiateService(final ConnectionContext connectionContext) {
+
+        if (ConnectionContext.CONNECTION_STATE.RIP.equals(connectionContext.getConnectionState())) {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Connection to the device {} was interrupted.", this.deviceContext.getDeviceInfo().getLOGValue());
+            }
+            return false;
+        }
+
+        LOG.info("Caching flows IDs ...");
+        fillDeviceFlowRegistry();
+        return true;
+    }
 }
index ed40598d2536f74fb1a86f4289018645bd846698..0a1f81095baed3b82ea9f2da1522271bd1a2472c 100644 (file)
@@ -23,8 +23,10 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
 import org.opendaylight.openflowplugin.api.OFConstants;
+import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
 import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
+import org.opendaylight.openflowplugin.api.openflow.device.handlers.ClusterInitializationPhaseHandler;
 import org.opendaylight.openflowplugin.api.openflow.role.RoleContext;
 import org.opendaylight.openflowplugin.api.openflow.role.RoleManager;
 import org.opendaylight.openflowplugin.impl.rpc.AbstractRequestContext;
@@ -53,6 +55,7 @@ class RoleContextImpl implements RoleContext {
     private final DeviceInfo deviceInfo;
     private CONTEXT_STATE state;
     private final RoleManager myManager;
+    private ClusterInitializationPhaseHandler clusterInitializationPhaseHandler;
 
     RoleContextImpl(final DeviceInfo deviceInfo,
                     final HashedWheelTimer hashedWheelTimer,
@@ -181,4 +184,33 @@ class RoleContextImpl implements RoleContext {
         return JdkFutureAdapters.listenInPoolThread(setRoleOutputFuture);
     }
 
+    @Override
+    public void setLifecycleInitializationPhaseHandler(final ClusterInitializationPhaseHandler handler) {
+        this.clusterInitializationPhaseHandler = handler;
+    }
+
+    @Override
+    public boolean onContextInstantiateService(final ConnectionContext connectionContext) {
+
+        if (connectionContext.getConnectionState().equals(ConnectionContext.CONNECTION_STATE.RIP)) {
+            LOG.warn("Connection on device {} was interrupted, will stop starting master services.", deviceInfo.getLOGValue());
+            return false;
+        }
+
+        Futures.addCallback(sendRoleChangeToDevice(OfpRole.BECOMEMASTER), new FutureCallback<RpcResult<SetRoleOutput>>() {
+            @Override
+            public void onSuccess(@Nullable RpcResult<SetRoleOutput> setRoleOutputRpcResult) {
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("Role MASTER was successfully set on device, node {}", deviceInfo.getLOGValue());
+                }
+            }
+
+            @Override
+            public void onFailure(final Throwable throwable) {
+                LOG.warn("Was not able to set MASTER role on device, node {}", deviceInfo.getLOGValue());
+            }
+        });
+
+        return this.clusterInitializationPhaseHandler.onContextInstantiateService(connectionContext);
+    }
 }
index e6decb4a7c9a74a89b423b54c71476830f8ee298..4a1ca41033c3d4d55fc66e9395572d7801d5c475 100644 (file)
@@ -25,7 +25,6 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
-import org.opendaylight.openflowplugin.api.openflow.OFPContext;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
 import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceInitializationPhaseHandler;
@@ -152,8 +151,4 @@ public class RoleManagerImpl implements RoleManager {
         return contexts.get(deviceInfo);
     }
 
-    @Override
-    public <T extends OFPContext> T gainContext(final DeviceInfo deviceInfo) {
-        return (T) contexts.get(deviceInfo);
-    }
 }
index 6d1954d30d6870fbb5c33f64d73ccfdfdb7d07dc..fec32b5489e0df1a7619d999662701ca87c7d854 100644 (file)
@@ -16,15 +16,16 @@ import java.util.Iterator;
 import java.util.Map.Entry;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Semaphore;
 import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
+import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
 import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
+import org.opendaylight.openflowplugin.api.openflow.device.handlers.ClusterInitializationPhaseHandler;
 import org.opendaylight.openflowplugin.api.openflow.rpc.RpcContext;
 import org.opendaylight.openflowplugin.api.openflow.statistics.ofpspecific.MessageSpy;
 import org.opendaylight.openflowplugin.extension.api.core.extension.ExtensionConverterProvider;
@@ -54,6 +55,7 @@ class RpcContextImpl implements RpcContext {
     private final ExtensionConverterProvider extensionConverterProvider;
     private final ConvertorExecutor convertorExecutor;
     private final NotificationPublishService notificationPublishService;
+    private ClusterInitializationPhaseHandler clusterInitializationPhaseHandler;
 
     RpcContextImpl(final DeviceInfo deviceInfo,
                    final RpcProviderRegistry rpcProviderRegistry,
@@ -200,7 +202,24 @@ class RpcContextImpl implements RpcContext {
     }
 
     @Override
-    public void startupClusterServices() throws ExecutionException, InterruptedException {
+    public ListenableFuture<Void> stopClusterServices(boolean deviceDisconnected) {
+        MdSalRegistrationUtils.unregisterServices(this);
+        return Futures.immediateFuture(null);
+    }
+
+    @Override
+    public void setLifecycleInitializationPhaseHandler(final ClusterInitializationPhaseHandler handler) {
+        this.clusterInitializationPhaseHandler = handler;
+    }
+
+    @Override
+    public boolean onContextInstantiateService(final ConnectionContext connectionContext) {
+
+        if (connectionContext.getConnectionState().equals(ConnectionContext.CONNECTION_STATE.RIP)) {
+            LOG.warn("Connection on device {} was interrupted, will stop starting master services.", deviceInfo.getLOGValue());
+            return false;
+        }
+
         MdSalRegistrationUtils.registerServices(this, deviceContext, extensionConverterProvider, convertorExecutor);
         if (isStatisticsRpcEnabled) {
             MdSalRegistrationUtils.registerStatCompatibilityServices(
@@ -209,12 +228,6 @@ class RpcContextImpl implements RpcContext {
                     notificationPublishService,
                     convertorExecutor);
         }
-
-    }
-
-    @Override
-    public ListenableFuture<Void> stopClusterServices(boolean deviceDisconnected) {
-        MdSalRegistrationUtils.unregisterServices(this);
-        return Futures.immediateFuture(null);
+        return this.clusterInitializationPhaseHandler.onContextInstantiateService(connectionContext);
     }
 }
index 22c4e18693d3d1c4458701265eaddbf36d63924a..11f30f644f79ddbd2d73700d4211a69e11a64de2 100644 (file)
@@ -16,7 +16,6 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
-import org.opendaylight.openflowplugin.api.openflow.OFPContext;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
 import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceInitializationPhaseHandler;
@@ -118,11 +117,6 @@ public class RpcManagerImpl implements RpcManager {
         }
     }
 
-    @Override
-    public <T extends OFPContext> T gainContext(DeviceInfo deviceInfo) {
-        return (T) contexts.get(deviceInfo);
-    }
-
 
     @Override
     public void setStatisticsRpcEnabled(boolean statisticsRpcEnabled) {
index 310f5842ad6ec268e9a7989332c0a5d221bdbfcc..13c8e995949e27f561cb979eda3f1a030f2f1ff0 100644 (file)
@@ -23,7 +23,6 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Optional;
-import java.util.concurrent.ExecutionException;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import javax.annotation.concurrent.GuardedBy;
@@ -34,6 +33,7 @@ import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceState;
 import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
+import org.opendaylight.openflowplugin.api.openflow.device.handlers.ClusterInitializationPhaseHandler;
 import org.opendaylight.openflowplugin.api.openflow.lifecycle.LifecycleService;
 import org.opendaylight.openflowplugin.api.openflow.rpc.listener.ItemLifecycleListener;
 import org.opendaylight.openflowplugin.api.openflow.statistics.StatisticsContext;
@@ -73,6 +73,8 @@ class StatisticsContextImpl implements StatisticsContext {
 
     private volatile boolean schedulingEnabled;
     private volatile CONTEXT_STATE state;
+    private ClusterInitializationPhaseHandler clusterInitializationPhaseHandler;
+    private ClusterInitializationPhaseHandler initialSubmitHandler;
 
     StatisticsContextImpl(@Nonnull final DeviceInfo deviceInfo,
                           final boolean shuttingDownStatisticsPolling,
@@ -427,15 +429,6 @@ class StatisticsContextImpl implements StatisticsContext {
         return this.deviceInfo;
     }
 
-    @Override
-    public void startupClusterServices() throws ExecutionException, InterruptedException {
-        if (!this.shuttingDownStatisticsPolling) {
-            this.statListForCollectingInitialization();
-            this.initialGatherDynamicData();
-            myManager.startScheduling(deviceInfo);
-        }
-    }
-
     @Override
     public ListenableFuture<Void> stopClusterServices(boolean deviceDisconnected) {
         myManager.stopScheduling(deviceInfo);
@@ -446,4 +439,48 @@ class StatisticsContextImpl implements StatisticsContext {
     public LifecycleService getLifecycleService() {
         return lifecycleService;
     }
+
+    @Override
+    public void setLifecycleInitializationPhaseHandler(final ClusterInitializationPhaseHandler handler) {
+        this.clusterInitializationPhaseHandler = handler;
+    }
+
+    @Override
+    public boolean onContextInstantiateService(final ConnectionContext connectionContext) {
+
+        if (connectionContext.getConnectionState().equals(ConnectionContext.CONNECTION_STATE.RIP)) {
+            LOG.warn("Connection on device {} was interrupted, will stop starting master services.", deviceInfo.getLOGValue());
+            return false;
+        }
+
+        if (!this.shuttingDownStatisticsPolling) {
+
+            LOG.info("Starting statistics context cluster services for node {}", deviceInfo.getLOGValue());
+
+            this.statListForCollectingInitialization();
+            Futures.addCallback(this.initialGatherDynamicData(), new FutureCallback<Boolean>() {
+
+                        @Override
+                        public void onSuccess(@Nullable Boolean aBoolean) {
+                            initialSubmitHandler.initialSubmitTransaction();
+                        }
+
+                        @Override
+                        public void onFailure(Throwable throwable) {
+                            LOG.warn("Initial gathering statistics unsuccessful for node {}", deviceInfo.getLOGValue());
+                            lifecycleService.closeConnection();
+                        }
+                    });
+
+                    myManager.startScheduling(deviceInfo);
+
+        }
+
+        return this.clusterInitializationPhaseHandler.onContextInstantiateService(connectionContext);
+    }
+
+    @Override
+    public void setInitialSubmitHandler(final ClusterInitializationPhaseHandler initialSubmitHandler) {
+        this.initialSubmitHandler = initialSubmitHandler;
+    }
 }
index 06e7863e3eb5e0e1f5adcffbed139b9730c0b83b..6d726ad071f13cb10c1b30aa4575795f200c9502 100644 (file)
@@ -30,7 +30,6 @@ import java.util.concurrent.TimeUnit;
 import javax.annotation.Nonnull;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
-import org.opendaylight.openflowplugin.api.openflow.OFPContext;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceState;
@@ -307,8 +306,4 @@ public class StatisticsManagerImpl implements StatisticsManager, StatisticsManag
         this.deviceTerminPhaseHandler = handler;
     }
 
-    @Override
-    public <T extends OFPContext> T gainContext(DeviceInfo deviceInfo) {
-        return (T) contexts.get(deviceInfo);
-    }
 }
index dabde3e24da6a35f2f02c6bc515dd7f5c0158177..21f3f9460b838c67d883b7fefc6e57ca11ea84f9 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ * Copyright (c) 2016 Pantheon Technologies s.r.o. and others. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -20,6 +20,7 @@ import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
+import org.opendaylight.openflowplugin.api.openflow.device.handlers.ClusterInitializationPhaseHandler;
 import org.opendaylight.openflowplugin.api.openflow.lifecycle.LifecycleService;
 import org.opendaylight.openflowplugin.api.openflow.registry.flow.DeviceFlowRegistry;
 import org.opendaylight.openflowplugin.api.openflow.role.RoleContext;
@@ -58,6 +59,7 @@ public class LifecycleServiceImplTest {
         lifecycleService.setRpcContext(rpcContext);
         lifecycleService.setRoleContext(roleContext);
         lifecycleService.setStatContext(statContext);
+        lifecycleService.registerService(clusterSingletonServiceProvider);
         Mockito.when(deviceContext.getDeviceInfo()).thenReturn(deviceInfo);
         Mockito.when(deviceContext.getPrimaryConnectionContext()).thenReturn(connectionContext);
         Mockito.when(deviceContext.getDeviceFlowRegistry()).thenReturn(deviceFlowRegistry);
@@ -70,11 +72,11 @@ public class LifecycleServiceImplTest {
     @Test
     public void instantiateServiceInstance() throws Exception {
         lifecycleService.instantiateServiceInstance();
-        Mockito.verify(deviceContext).startupClusterServices();
-        Mockito.verify(statContext).startupClusterServices();
-        Mockito.verify(deviceContext).initialSubmitTransaction();
-        Mockito.verify(rpcContext).startupClusterServices();
-        Mockito.verify(roleContext).startupClusterServices();
+        Mockito.verify(deviceContext).setLifecycleInitializationPhaseHandler(Mockito.<ClusterInitializationPhaseHandler>any());
+        Mockito.verify(statContext).setLifecycleInitializationPhaseHandler(Mockito.<ClusterInitializationPhaseHandler>any());
+        Mockito.verify(statContext).setInitialSubmitHandler(Mockito.<ClusterInitializationPhaseHandler>any());
+        Mockito.verify(rpcContext).setLifecycleInitializationPhaseHandler(Mockito.<ClusterInitializationPhaseHandler>any());
+        Mockito.verify(roleContext).setLifecycleInitializationPhaseHandler(Mockito.<ClusterInitializationPhaseHandler>any());
     }
 
     @Test