Fix NPEs on switch disconnect in cluster mode 53/1153/2
authorYevgeny Khodorkovsky <ykhodork@cisco.com>
Wed, 11 Sep 2013 03:24:47 +0000 (20:24 -0700)
committerYevgeny Khodorkovsky <ykhodork@cisco.com>
Wed, 11 Sep 2013 22:20:07 +0000 (15:20 -0700)
- Fixed null pointer exceptions on switch disconnect that was
  connected to 2 or more controllers in "Any controller-One master" scheme
- Added node count to clustered controllers table in UI

Change-Id: I0c322a7a4105955a545b24a9ba1f36743800a802
Signed-off-by: Yevgeny Khodorkovsky <ykhodork@cisco.com>
opendaylight/connectionmanager/implementation/src/main/java/org/opendaylight/controller/connectionmanager/scheme/AbstractScheme.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DiscoveryService.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/InventoryServiceShim.java
opendaylight/web/root/src/main/java/org/opendaylight/controller/web/ClusterNodeBean.java
opendaylight/web/root/src/main/java/org/opendaylight/controller/web/DaylightWebAdmin.java
opendaylight/web/root/src/main/resources/js/open.js

index f4c7bd2ff77fcda8874ca39db7d7c404ccf04aa7..06b72219f7fbddc5b5b17357f421f003691a36f7 100644 (file)
@@ -10,8 +10,6 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
-import javax.transaction.SystemException;
-
 import org.opendaylight.controller.clustering.services.CacheConfigException;
 import org.opendaylight.controller.clustering.services.CacheExistException;
 import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
@@ -128,7 +126,6 @@ public abstract class AbstractScheme {
         return controllerNodesMap.get(controller);
     }
 
-    @SuppressWarnings("deprecation")
     public Set<Node> getNodes() {
         return getNodes(clusterServices.getMyAddress());
     }
@@ -142,7 +139,6 @@ public abstract class AbstractScheme {
         return nodeConnections;
     }
 
-    @SuppressWarnings("deprecation")
     public boolean isLocal(Node node) {
         if (nodeConnections == null) return false;
         InetAddress myController = clusterServices.getMyAddress();
@@ -150,7 +146,6 @@ public abstract class AbstractScheme {
         return (controllers != null && controllers.contains(myController));
     }
 
-    @SuppressWarnings("deprecation")
     public Status removeNode (Node node) {
         return removeNodeFromController(node, clusterServices.getMyAddress());
     }
index 0895d9af27c85132965a98ea23cd166784a3e538..869d36d9cbf815142b430e093a72fb22aedfd439 100644 (file)
@@ -33,17 +33,11 @@ import org.opendaylight.controller.protocol_plugin.openflow.IInventoryProvider;
 import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimExternalListener;
 import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
 import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
-import org.openflow.protocol.OFPhysicalPort;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import org.opendaylight.controller.sal.connection.IPluginOutConnectionService;
 import org.opendaylight.controller.sal.core.Config;
 import org.opendaylight.controller.sal.core.ConstructionException;
-import org.opendaylight.controller.sal.core.Edge;
 import org.opendaylight.controller.sal.core.ContainerFlow;
+import org.opendaylight.controller.sal.core.Edge;
 import org.opendaylight.controller.sal.core.IContainerListener;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
@@ -61,6 +55,11 @@ import org.opendaylight.controller.sal.utils.HexEncode;
 import org.opendaylight.controller.sal.utils.NetUtils;
 import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
 import org.opendaylight.controller.sal.utils.NodeCreator;
+import org.openflow.protocol.OFPhysicalPort;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * The class describes neighbor discovery service for an OpenFlow network.
@@ -561,10 +560,11 @@ public class DiscoveryService implements IInventoryShimExternalListener, IDataPa
     private void addDiscovery(Node node) {
         Map<Long, ISwitch> switches = controller.getSwitches();
         ISwitch sw = switches.get(node.getID());
-        List<OFPhysicalPort> ports = sw.getEnabledPorts();
-        if (ports == null) {
+        if (sw == null) {
+            //switch could be removed by now, stop propagation
             return;
         }
+        List<OFPhysicalPort> ports = sw.getEnabledPorts();
         for (OFPhysicalPort port : ports) {
             NodeConnector nodeConnector = NodeConnectorCreator.createOFNodeConnector(port.getPortNumber(), node);
             if (!readyListHi.contains(nodeConnector)) {
index 9e0179680612c52a46a194544471d1c0a88c19ca..92eec43b4ce58487465ae243c46aa3c0f87b6027 100644 (file)
@@ -482,8 +482,7 @@ public class InventoryServiceShim implements IContainerListener,
         Set<Property> props = new HashSet<Property>();
         Long sid = (Long) node.getID();
 
-        Date connectedSince = controller.getSwitches().get(sid)
-                .getConnectedDate();
+        Date connectedSince = sw.getConnectedDate();
         Long connectedSinceTime = (connectedSince == null) ? 0 : connectedSince
                 .getTime();
         props.add(new TimeStamp(connectedSinceTime, "connectedSince"));
index 5e4f22afe2edc823afa29a45fcfa4c8b44da90c0..e59379916af8fba35f17da398458968fa01e8270 100644 (file)
@@ -11,6 +11,7 @@ public class ClusterNodeBean {
     private final String name;
     private final Boolean me;
     private final Boolean coordinator;
+    private final Integer numConnectedNodes;
 
     public static class Builder {
         // required params
@@ -20,6 +21,7 @@ public class ClusterNodeBean {
         // optional params
         private Boolean me = null;
         private Boolean coordinator = null;
+        private Integer numConnectedNodes = null;
 
         public Builder(InetAddress address) {
             this.address = address.getAddress();
@@ -36,6 +38,11 @@ public class ClusterNodeBean {
             return this;
         }
 
+        public Builder nodesConnected(int numNodes) {
+            this.numConnectedNodes = numNodes;
+            return this;
+        }
+
         public ClusterNodeBean build() {
             return new ClusterNodeBean(this);
         }
@@ -46,5 +53,6 @@ public class ClusterNodeBean {
         this.name = builder.name;
         this.me = builder.me;
         this.coordinator = builder.coordinator;
+        this.numConnectedNodes = builder.numConnectedNodes;
     }
 }
\ No newline at end of file
index 3b0b85c065cc8cf2de88205525aaaf6f89e84868..13a3a10667906c571d69ef1d9dac0229b7c85a15 100644 (file)
@@ -55,15 +55,29 @@ public class DaylightWebAdmin {
         if (clusterServices == null) {
             return null;
         }
+        IConnectionManager connectionManager = (IConnectionManager) ServiceHelper.getGlobalInstance(
+                IConnectionManager.class, this);
+        if (connectionManager == null) {
+            return null;
+        }
 
         List<ClusterNodeBean> clusterNodes = new ArrayList<ClusterNodeBean>();
 
         List<InetAddress> controllers = clusterServices.getClusteredControllers();
         for (InetAddress controller : controllers) {
             ClusterNodeBean.Builder clusterBeanBuilder = new ClusterNodeBean.Builder(controller);
+
+            //get number of connected nodes
+            Set<Node> connectedNodes = connectionManager.getNodes(controller);
+            int numNodes = connectedNodes == null ? 0 : connectedNodes.size();
+            clusterBeanBuilder.nodesConnected(numNodes);
+
+            //determine if this is the executing controller
             if (controller.equals(clusterServices.getMyAddress())) {
                 clusterBeanBuilder.highlightMe();
             }
+
+            //determine whether this is coordinator
             if (clusterServices.getCoordinatorAddress().equals(controller)) {
                 clusterBeanBuilder.iAmCoordinator();
             }
index b2502ad71ae473b2ca157bf0f79b3fe0d74bf2ed..43a7dfdc443ab7447fb472dc31afa1b83402f9d7 100644 (file)
@@ -562,9 +562,9 @@ one.main.cluster = {
   data : function(data) {
     var tdata = [];
     var registry = [];
-    $(data).each(function(idx, val) {
-      var name = val.name;
-      var address = val.address;
+    $(data).each(function(idx, controller) {
+      var name = controller.name;
+      var address = controller.address;
       var $registry = $(document.createElement('span'));
       $registry
       .append(JSON.stringify(address))
@@ -572,26 +572,32 @@ one.main.cluster = {
       .addClass('ux-id');
     name = one.lib.dashlet.label(name, null)[0].outerHTML;
     name += $registry[0].outerHTML;
-    if (val.me === true) {
+    if (controller.me === true) {
       var me = one.lib.dashlet.label('*', 'label-inverse')[0].outerHTML;
       name += '&nbsp;'+me;
     }
-    if (val.coordinator === true) {
+    if (controller.coordinator === true) {
       var coord = one.lib.dashlet.label('C')[0].outerHTML;
       name += '&nbsp;'+coord;
     }
     tdata.push({
-      'controller' : name
+      'controller' : name,
+      'numNodes'   : controller.numConnectedNodes
     });
     });
     var source = new StaticDataSource({
-      columns : [
-    {
-      property : 'controller',
-        label : 'Controller',
-        sortable : true
-    }
-    ],
+        columns : [
+            {
+              property : 'controller',
+                label : 'Controller',
+                sortable : true
+            },
+            {
+                property : 'numNodes',
+                label    : 'Nodes',
+                sortable : true
+            }
+        ],
         data : tdata,
         delay : 0
     });