Merge "Decouple IContainerListener to avoid parallel computation in cluster"
authorMadhu Venugopal <vmadhu@cisco.com>
Fri, 27 Sep 2013 19:14:18 +0000 (19:14 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Fri, 27 Sep 2013 19:14:18 +0000 (19:14 +0000)
opendaylight/clustering/services/src/main/java/org/opendaylight/controller/clustering/services/IClusterServices.java
opendaylight/clustering/services_implementation/src/main/java/org/opendaylight/controller/clustering/services_implementation/internal/ClusterManager.java
opendaylight/clustering/services_implementation/src/test/java/org/opendaylight/controller/clustering/services_implementation/internal/ClusterManagerTest.java
opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/FlowEntryDistributionOrderFutureTask.java
opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java
opendaylight/web/devices/src/main/java/org/opendaylight/controller/devices/web/Devices.java
opendaylight/web/devices/src/main/resources/js/page.js
opendaylight/web/flows/src/main/resources/js/page.js

index 5551f23f7220fe0908f0ab37faa9858cca956a75..77e300e95aaa7475b276fa10eaa8f37bb9326d5b 100644 (file)
@@ -62,7 +62,19 @@ public interface IClusterServices {
          * immediately committed in the cache.
          *
          */
-        NON_TRANSACTIONAL;
+        NON_TRANSACTIONAL,
+        /**
+         * Set on a cache that can transfer the updates asynchronously from the
+         * calling thread. The caller when doing put/clear/remove cannot expect
+         * that the operation has happened clusterwide
+         */
+        ASYNC,
+        /**
+         * Set on a cache that transfer the updates synchronously to the calling
+         * thread so when getting back the operation is supposed to have
+         * completed on all the cluster nodes. Slow but safe.
+         */
+        SYNC;
     }
 
     /**
@@ -237,6 +249,7 @@ public interface IClusterServices {
      *
      * @return true if the role is the one of standby, else false
      */
+    @Deprecated
     boolean amIStandby();
 
     /**
@@ -247,6 +260,7 @@ public interface IClusterServices {
      *
      * @return Address of the active controller
      */
+    @Deprecated
     InetAddress getActiveAddress();
 
     /**
@@ -271,6 +285,7 @@ public interface IClusterServices {
      *
      * @param i Interface that will be called when the Role Change happens
      */
+    @Deprecated
     void listenRoleChange(IListenRoleChange i)
             throws ListenRoleChangeAddException;
 
@@ -281,5 +296,6 @@ public interface IClusterServices {
      *
      * @param i Interface that will be called when the Role Change happens
      */
+    @Deprecated
     void unlistenRoleChange(IListenRoleChange i);
 }
index 4a67e76ab25b5e92e63e7433cd9efdea5934a7af..518bf7b1a84f9742e589dd37d21432e6ee42dcb0 100644 (file)
@@ -33,6 +33,7 @@ import javax.transaction.TransactionManager;
 
 import org.infinispan.Cache;
 import org.infinispan.configuration.cache.Configuration;
+import org.infinispan.configuration.cache.ConfigurationBuilder;
 import org.infinispan.configuration.global.GlobalConfigurationBuilder;
 import org.infinispan.configuration.parsing.ConfigurationBuilderHolder;
 import org.infinispan.configuration.parsing.ParserRegistry;
@@ -235,6 +236,17 @@ public class ClusterManager implements IClusterServices {
         return res;
     }
 
+    private void exitOnSecurityException(Exception ioe) {
+        Throwable cause = ioe.getCause();
+        while (cause != null) {
+            if (cause instanceof java.lang.SecurityException) {
+                logger.error("Failed Cluster authentication. Stopping Controller...");
+                System.exit(0);
+            }
+            cause = cause.getCause();
+        }
+    }
+
     public void start() {
         this.gossiper = startGossiper();
         if (this.gossiper != null) {
@@ -271,6 +283,7 @@ public class ClusterManager implements IClusterServices {
             logger.error("Stack Trace that raised th exception");
             logger.error("",ioe);
             this.cm = null;
+            exitOnSecurityException(ioe);
             this.stop();
         }
         logger.debug("Cache Manager has value {}", this.cm);
@@ -304,24 +317,54 @@ public class ClusterManager implements IClusterServices {
             throw new CacheExistException();
         }
 
-        // Sanity check to avoid contrasting parameters
-        if (cMode.containsAll(EnumSet.of(
-                IClusterServices.cacheMode.NON_TRANSACTIONAL,
+        // Sanity check to avoid contrasting parameters between transactional
+        // and not
+        if (cMode.containsAll(EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL,
                 IClusterServices.cacheMode.TRANSACTIONAL))) {
             throw new CacheConfigException();
         }
 
-        if (cMode.contains(IClusterServices.cacheMode.NON_TRANSACTIONAL)) {
-            c = manager.getCache(realCacheName);
-            return c;
-        } else if (cMode.contains(IClusterServices.cacheMode.TRANSACTIONAL)) {
-            Configuration rc = manager
-                    .getCacheConfiguration("transactional-type");
-            manager.defineConfiguration(realCacheName, rc);
-            c = manager.getCache(realCacheName);
-            return c;
+        // Sanity check to avoid contrasting parameters between sync and async
+        if (cMode.containsAll(EnumSet.of(IClusterServices.cacheMode.SYNC, IClusterServices.cacheMode.ASYNC))) {
+            throw new CacheConfigException();
         }
-        return null;
+
+        Configuration fromTemplateConfig = null;
+        /*
+         * Fetch transactional/non-transactional templates
+         */
+        // Check if transactional
+        if (cMode.contains(IClusterServices.cacheMode.TRANSACTIONAL)) {
+            fromTemplateConfig = manager.getCacheConfiguration("transactional-type");
+        } else if (cMode.contains(IClusterServices.cacheMode.NON_TRANSACTIONAL)) {
+            fromTemplateConfig = manager.getDefaultCacheConfiguration();
+        }
+
+        // If none set the transactional property then just return null
+        if (fromTemplateConfig == null) {
+            return null;
+        }
+
+        ConfigurationBuilder builder = new ConfigurationBuilder();
+        builder.read(fromTemplateConfig);
+        /*
+         * Now evaluate async/sync
+         */
+        if (cMode.contains(IClusterServices.cacheMode.ASYNC)) {
+            builder.clustering()
+                    .cacheMode(fromTemplateConfig.clustering()
+                            .cacheMode()
+                            .toAsync());
+        } else if (cMode.contains(IClusterServices.cacheMode.SYNC)) {
+            builder.clustering()
+                    .cacheMode(fromTemplateConfig.clustering()
+                            .cacheMode()
+                            .toSync());
+        }
+
+        manager.defineConfiguration(realCacheName, builder.build());
+        c = manager.getCache(realCacheName);
+        return c;
     }
 
     @Override
index 736a2b23ec8d9e63b074d2c7b194f6ae2b034859..ab0b63eb6db8dfbab86315c3f3638c1439cb4f69 100644 (file)
@@ -89,8 +89,22 @@ public class ClusterManagerTest {
             Assert.assertTrue(true);
         }
 
-        // Create second cache properly this time, as non_transactional
+        // Create second cache NON_TRANSACTIONAL but with both ASYNC and SYNC,
+        // expect to complain
         cacheModeSet.remove(cacheMode.TRANSACTIONAL);
+        cacheModeSet.add(cacheMode.SYNC);
+        cacheModeSet.add(cacheMode.ASYNC);
+        try {
+            c2 = (CacheImpl<String, Integer>) cm.createCache("Container1", "Cache2", cacheModeSet);
+        } catch (CacheExistException cee) {
+            Assert.assertTrue(false);
+        } catch (CacheConfigException cce) {
+            Assert.assertTrue(true);
+        }
+
+        // Create second cache properly this time, as non_transactional and
+        // ASYNC
+        cacheModeSet.remove(cacheMode.SYNC);
         try {
             c2 = (CacheImpl<String, Integer>) cm.createCache("Container1",
                     "Cache2", cacheModeSet);
index 0c105bae1e8f462a6a32af6fd826152d860ade9f..b8c2d1db55067b9fc880ccfa74d352a0a45965a0 100644 (file)
@@ -65,6 +65,12 @@ final class FlowEntryDistributionOrderFutureTask implements Future<Status> {
 
     @Override
     public boolean cancel(boolean mayInterruptIfRunning) {
+        if (this.waitingLatch.getCount() != 0L) {
+            this.retStatus = new Status(StatusCode.GONE);
+            this.waitingLatch.countDown();
+            logger.trace("Cancelled the workOrder");
+            return true;
+        }
         return false;
     }
 
index a77224af8a172ed396addb3dbeab3c2dd8939361..f12074b22fd44534526394f064e0ce0c24f26312 100644 (file)
@@ -1379,10 +1379,10 @@ public class ForwardingRulesManager implements
                     EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
 
             clusterContainerService.createCache(WORKSTATUSCACHE,
EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
                   EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL, IClusterServices.cacheMode.ASYNC));
 
             clusterContainerService.createCache(WORKORDERCACHE,
EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
                   EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL, IClusterServices.cacheMode.ASYNC));
 
         } catch (CacheConfigException cce) {
             log.error("CacheConfigException");
@@ -1882,7 +1882,9 @@ public class ForwardingRulesManager implements
      * If requested, a copy of each original flow entry will be stored in the
      * inactive list so that it can be re-applied when needed (This is typically
      * the case when running in the default container and controller moved to
-     * container mode)
+     * container mode) NOTE WELL: The routine as long as does a bulk change will
+     * operate only on the entries for nodes locally attached so to avoid
+     * redundant operations initiated by multiple nodes
      *
      * @param preserveFlowEntries
      *            if true, a copy of each original entry is stored in the
@@ -1908,9 +1910,15 @@ public class ForwardingRulesManager implements
 
         // Now remove the entries
         for (FlowEntryInstall flowEntryHw : toRemove) {
-            Status status = this.removeEntryInternal(flowEntryHw, false);
-            if (!status.isSuccess()) {
-                log.warn("Failed to remove entry: {}. The failure is: {}", flowEntryHw, status.getDescription());
+            Node n = flowEntryHw.getNode();
+            if (n != null && connectionManager.getLocalityStatus(n) == ConnectionLocality.LOCAL) {
+                Status status = this.removeEntryInternal(flowEntryHw, false);
+                if (!status.isSuccess()) {
+                    log.warn("Failed to remove entry: {}. The failure is: {}", flowEntryHw, status.getDescription());
+                }
+            } else {
+                log.debug("Not removing entry {} because not connected locally, the remote guy will do it's job",
+                        flowEntryHw);
             }
         }
     }
@@ -2647,6 +2655,12 @@ public class ForwardingRulesManager implements
         uninstallAllFlowEntries(false);
         // Shutdown executor
         this.executor.shutdownNow();
+        // Now walk all the workMonitor and wake up the one sleeping because
+        // destruction is happening
+        for (FlowEntryDistributionOrder fe : workMonitor.keySet()) {
+            FlowEntryDistributionOrderFutureTask task = workMonitor.get(fe);
+            task.cancel(true);
+        }
     }
 
     public void setFlowProgrammerService(IFlowProgrammerService service) {
index 34688cbb634eeede8c0ebfae25a121e673712bf4..6987ea9827547783e10da1f2af4ca4d0d1f8b5ea 100644 (file)
@@ -130,7 +130,7 @@ public class Devices implements IDaylightWeb {
                 nodeDatum.put("mode", modeStr);
 
                 nodeDatum.put("json", gson.toJson(nodeDatum));
-                nodeDatum.put("mac", HexEncode.bytesToHexString(device.getDataLayerAddress()));
+                nodeDatum.put("mac", HexEncode.bytesToHexStringFormat(device.getDataLayerAddress()));
                 StringBuffer sb1 = new StringBuffer();
                 Set<NodeConnector> nodeConnectorSet = device.getNodeConnectors();
                 if (nodeConnectorSet != null && nodeConnectorSet.size() > 0) {
index 90352602cd119daca080abbaf2ff1fb956576d9c..b02a15a7e5748f96368e425d2a374f04f1647b74 100644 (file)
@@ -278,7 +278,7 @@ one.f.switchmanager.nodesLearnt = {
         footer: {
             updateNode: function() {
                 var footer = [];
-                var saveButton = one.lib.dashlet.button.single("Save", one.f.switchmanager.nodesLearnt.id.modal.save, "btn-success", "");
+                var saveButton = one.lib.dashlet.button.single("Save", one.f.switchmanager.nodesLearnt.id.modal.save, "btn-primary", "");
                 var $saveButton = one.lib.dashlet.button.button(saveButton);
                 footer.push($saveButton);
 
@@ -356,7 +356,7 @@ one.f.switchmanager.nodesLearnt = {
                         },
                         {
                             property: 'mac',
-                            label: 'MAC',
+                            label: 'MAC Address',
                             sortable: true
                         },
                         {
@@ -516,6 +516,10 @@ one.f.switchmanager.subnetGatewayConfig = {
                     one.f.switchmanager.subnetGatewayConfig.id.dashlet.addPorts, "btn-primary", "btn-mini");
                 var $button = one.lib.dashlet.button.button(button);
                 $button.click(function() {
+                    if (one.f.switchmanager.subnetGatewayConfig.registry.gateways.length === 0) {
+                      alert('No Gateways Exist');
+                      return false;
+                    }
                     var $modal = one.f.switchmanager.subnetGatewayConfig.modal.initialize.ports();
                     $modal.modal();
                 });
@@ -649,8 +653,9 @@ one.f.switchmanager.subnetGatewayConfig = {
                 // gateway IP Mask 
                 var $label = one.lib.form.label("Gateway IP Address/Mask");
                 var $input = one.lib.form.input("Gateway IP Address/Mask");
+                var $help = one.lib.form.help('Example: 192.168.10.254/16');
                 $input.attr('id', one.f.switchmanager.subnetGatewayConfig.id.modal.form.gatewayIPAddress);
-                $fieldset.append($label).append($input);
+                $fieldset.append($label).append($input).append($help);
                 
                 $form.append($fieldset);
                 return $form;
@@ -662,6 +667,7 @@ one.f.switchmanager.subnetGatewayConfig = {
                 var $label = one.lib.form.label("Gateway Name");
                 var $select = one.lib.form.select.create(one.f.switchmanager.subnetGatewayConfig.registry.gateways);
                 $select.attr('id', one.f.switchmanager.subnetGatewayConfig.id.modal.form.name);
+                one.lib.form.select.prepend($select, { '' : 'Please Select a Gateway' });
                 $select.val($select.find("option:first").val());
                 $fieldset.append($label).append($select);
 
@@ -692,6 +698,7 @@ one.f.switchmanager.subnetGatewayConfig = {
                 // ports
                 var $label = one.lib.form.label("Select Port");
                 var $select = one.lib.form.select.create();
+                one.lib.form.select.prepend($select, { '' : 'Please Select a Port' });
                 $select.attr('id', one.f.switchmanager.subnetGatewayConfig.id.modal.form.ports);
                 $fieldset.append($label).append($select);
                 
@@ -713,7 +720,7 @@ one.f.switchmanager.subnetGatewayConfig = {
         },
         footer : function() {
             var footer = [];
-            var saveButton = one.lib.dashlet.button.single("Save", one.f.switchmanager.subnetGatewayConfig.id.modal.save, "btn-success", "");
+            var saveButton = one.lib.dashlet.button.single("Save", one.f.switchmanager.subnetGatewayConfig.id.modal.save, "btn-primary", "");
             var $saveButton = one.lib.dashlet.button.button(saveButton);
             footer.push($saveButton);
             return footer;
@@ -1042,13 +1049,15 @@ one.f.switchmanager.staticRouteConfig = {
             // static route IP Mask 
             var $label = one.lib.form.label("Static Route");
             var $input = one.lib.form.input("Static Route");
+            var $help = one.lib.form.help('Example: 53.55.0.0/16');
             $input.attr('id', one.f.switchmanager.staticRouteConfig.id.modal.form.staticRoute);
-            $fieldset.append($label).append($input);
+            $fieldset.append($label).append($input).append($help);
             // static route IP Mask 
             var $label = one.lib.form.label("Next Hop");
             var $input = one.lib.form.input("Next Hop");
+            var $help = one.lib.form.help('Example: 192.168.10.254');
             $input.attr('id', one.f.switchmanager.staticRouteConfig.id.modal.form.nextHop);
-            $fieldset.append($label).append($input);
+            $fieldset.append($label).append($input).append($help);
             // return
             $form.append($fieldset);
             return $form;
@@ -1065,7 +1074,7 @@ one.f.switchmanager.staticRouteConfig = {
         },
         footer : function() {
             var footer = [];
-            var saveButton = one.lib.dashlet.button.single("Save", one.f.switchmanager.staticRouteConfig.id.modal.save, "btn-success", "");
+            var saveButton = one.lib.dashlet.button.single("Save", one.f.switchmanager.staticRouteConfig.id.modal.save, "btn-primary", "");
             var $saveButton = one.lib.dashlet.button.button(saveButton);
             footer.push($saveButton);
             return footer;
@@ -1334,20 +1343,24 @@ one.f.switchmanager.spanPortConfig = {
                 // retrieve port value
                 var nodeId = $(this).find('option:selected').attr('value');
                 one.f.switchmanager.spanPortConfig.registry['currentNode'] = nodeId;
-                var $ports = $('#' + one.f.switchmanager.spanPortConfig.id.modal.form.port);
+                var $ports = $('#'+one.f.switchmanager.spanPortConfig.id.modal.form.port);
                 var ports = one.f.switchmanager.spanPortConfig.registry['nodePorts'][nodeId]
                 var options = {};
                 $(ports).each(function(idx, val) {
                     options[val.internalPortName] = val.portName+' ('+val.portId+')'; 
                 });
                 one.lib.form.select.inject($ports, options); 
+                one.lib.form.select.prepend($ports, {'':'Please Select a Port'});
+                $ports.val($ports.find('option:first').val());
             });
 
             $fieldset.append($label).append($select);
             // input port
             var $label = one.lib.form.label("Input Port");
             var $select = one.lib.form.select.create();
+            one.lib.form.select.prepend($select, {'':'None'});
             $select.attr('id', one.f.switchmanager.spanPortConfig.id.modal.form.port);
+            $select.val($select.find('option:first').val());
             $fieldset.append($label).append($select);
             
             // return
@@ -1377,14 +1390,14 @@ one.f.switchmanager.spanPortConfig = {
         },
         footer : function() {
             var footer = [];
-            var saveButton = one.lib.dashlet.button.single("Save", one.f.switchmanager.spanPortConfig.id.modal.save, "btn-success", "");
+            var saveButton = one.lib.dashlet.button.single("Save", one.f.switchmanager.spanPortConfig.id.modal.save, "btn-primary", "");
             var $saveButton = one.lib.dashlet.button.button(saveButton);
             footer.push($saveButton);
             return footer;
         },
         removeMultiple: {
             dialog: function(spanPortsToDelete) {
-                var h3 = 'Remove Span Port';
+                var h3 = 'Remove SPAN Port';
                 
                 var footer = one.f.switchmanager.spanPortConfig.modal.removeMultiple.footer();
                 var $body = one.f.switchmanager.spanPortConfig.modal.removeMultiple.body(spanPortsToDelete);
index f3bbf7559b142b0375ea35e8d3f9c052152d284a..f0486c525c35aded862a2441184c48c5a3485b1a 100644 (file)
@@ -659,7 +659,8 @@ one.f.flows = {
             var $form = $(document.createElement('form'));
             var $fieldset = $(document.createElement('fieldset'));
             // flow description
-            var $legend = one.lib.form.legend("Flow Description");
+            var $legend = one.lib.form.legend("");
+            $legend.css('visibility', 'hidden');
             $fieldset.append($legend);
             // name
             var $label = one.lib.form.label("Name");
@@ -739,31 +740,27 @@ one.f.flows = {
             $fieldset.append($label).append($input).append($help);
             // srcMac
             var $label = one.lib.form.label("Source MAC Address");
-            var $input = one.lib.form.input("Source MAC Address");
+            var $input = one.lib.form.input("3c:97:0e:75:c3:f7");
             $input.attr('id', one.f.flows.id.modal.form.srcMac);
-            var $help = one.lib.form.help("Example: 00:11:22:aa:bb:cc");
-            $fieldset.append($label).append($input).append($help);
+            $fieldset.append($label).append($input);
             // dstMac
             var $label = one.lib.form.label("Destination MAC Address");
-            var $input = one.lib.form.input("Destination MAC Address");
+            var $input = one.lib.form.input("7c:d1:c3:e8:e6:99");
             $input.attr('id', one.f.flows.id.modal.form.dstMac);
-            var $help = one.lib.form.help("Example: 00:11:22:aa:bb:cc");
-            $fieldset.append($label).append($input).append($help);
+            $fieldset.append($label).append($input);
             // layer 3
             var $legend = one.lib.form.legend("Layer 3");
             $fieldset.append($legend);
             // srcIp
             var $label = one.lib.form.label("Source IP Address");
-            var $input = one.lib.form.input("Source IP Address");
+            var $input = one.lib.form.input("192.168.3.128");
             $input.attr('id', one.f.flows.id.modal.form.srcIp);
-            var $help = one.lib.form.help("Example: 127.0.0.1");
-            $fieldset.append($label).append($input).append($help);
+            $fieldset.append($label).append($input);
             // dstIp
             var $label = one.lib.form.label("Destination IP Address");
-            var $input = one.lib.form.input("Destination IP Address");
+            var $input = one.lib.form.input("2001:2334::0/32");
             $input.attr('id', one.f.flows.id.modal.form.dstIp);
-            var $help = one.lib.form.help("Example: 127.0.0.1");
-            $fieldset.append($label).append($input).append($help);
+            $fieldset.append($label).append($input);
             // tosBits
             var $label = one.lib.form.label("TOS Bits");
             var $input = one.lib.form.input("TOS Bits");