From: Yevgeny Khodorkovsky Date: Wed, 11 Sep 2013 03:24:47 +0000 (-0700) Subject: Fix NPEs on switch disconnect in cluster mode X-Git-Tag: releasepom-0.1.0~106 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=9092f24a69c54a4512cb1cdbb4ca2c3734a087d5 Fix NPEs on switch disconnect in cluster mode - 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 --- diff --git a/opendaylight/connectionmanager/implementation/src/main/java/org/opendaylight/controller/connectionmanager/scheme/AbstractScheme.java b/opendaylight/connectionmanager/implementation/src/main/java/org/opendaylight/controller/connectionmanager/scheme/AbstractScheme.java index f4c7bd2ff7..06b72219f7 100644 --- a/opendaylight/connectionmanager/implementation/src/main/java/org/opendaylight/controller/connectionmanager/scheme/AbstractScheme.java +++ b/opendaylight/connectionmanager/implementation/src/main/java/org/opendaylight/controller/connectionmanager/scheme/AbstractScheme.java @@ -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 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()); } diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DiscoveryService.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DiscoveryService.java index 0895d9af27..869d36d9cb 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DiscoveryService.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DiscoveryService.java @@ -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 switches = controller.getSwitches(); ISwitch sw = switches.get(node.getID()); - List ports = sw.getEnabledPorts(); - if (ports == null) { + if (sw == null) { + //switch could be removed by now, stop propagation return; } + List ports = sw.getEnabledPorts(); for (OFPhysicalPort port : ports) { NodeConnector nodeConnector = NodeConnectorCreator.createOFNodeConnector(port.getPortNumber(), node); if (!readyListHi.contains(nodeConnector)) { diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/InventoryServiceShim.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/InventoryServiceShim.java index 9e01796806..92eec43b4c 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/InventoryServiceShim.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/InventoryServiceShim.java @@ -482,8 +482,7 @@ public class InventoryServiceShim implements IContainerListener, Set props = new HashSet(); 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")); diff --git a/opendaylight/web/root/src/main/java/org/opendaylight/controller/web/ClusterNodeBean.java b/opendaylight/web/root/src/main/java/org/opendaylight/controller/web/ClusterNodeBean.java index 5e4f22afe2..e59379916a 100644 --- a/opendaylight/web/root/src/main/java/org/opendaylight/controller/web/ClusterNodeBean.java +++ b/opendaylight/web/root/src/main/java/org/opendaylight/controller/web/ClusterNodeBean.java @@ -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 diff --git a/opendaylight/web/root/src/main/java/org/opendaylight/controller/web/DaylightWebAdmin.java b/opendaylight/web/root/src/main/java/org/opendaylight/controller/web/DaylightWebAdmin.java index 3b0b85c065..13a3a10667 100644 --- a/opendaylight/web/root/src/main/java/org/opendaylight/controller/web/DaylightWebAdmin.java +++ b/opendaylight/web/root/src/main/java/org/opendaylight/controller/web/DaylightWebAdmin.java @@ -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 clusterNodes = new ArrayList(); List controllers = clusterServices.getClusteredControllers(); for (InetAddress controller : controllers) { ClusterNodeBean.Builder clusterBeanBuilder = new ClusterNodeBean.Builder(controller); + + //get number of connected nodes + Set 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(); } diff --git a/opendaylight/web/root/src/main/resources/js/open.js b/opendaylight/web/root/src/main/resources/js/open.js index b2502ad71a..43a7dfdc44 100644 --- a/opendaylight/web/root/src/main/resources/js/open.js +++ b/opendaylight/web/root/src/main/resources/js/open.js @@ -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 += ' '+me; } - if (val.coordinator === true) { + if (controller.coordinator === true) { var coord = one.lib.dashlet.label('C')[0].outerHTML; name += ' '+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 });