Choose ONOS nodes so that only one partition looses a majority

- Fix counter check to only look at the counters used by the test
- Add the gen-partition file to the repo and make the test copy it to
  the right place in ONOS
- clear buffer in clidriver after secureCopy
- Change individual ping timeout for ping functions in mininet driver
- increase links timeout in mininet driver due to occasional failures
- Kill iperf if it timesout to allow continued use of mininet
- Clear buffer at the end of many onos driver functions

Change-Id: I3c9235d1c6082f0ef86266405ed99c07e1b27fb5
diff --git a/TestON/tests/HAminorityRestart/dependencies/Counters.py b/TestON/tests/HAminorityRestart/dependencies/Counters.py
index 21308c2..6614887 100644
--- a/TestON/tests/HAminorityRestart/dependencies/Counters.py
+++ b/TestON/tests/HAminorityRestart/dependencies/Counters.py
@@ -1,14 +1,19 @@
 def __init__( self ):
     self.default = ''
 
-def counterCheck( counterName, counterValue ):
+def consistentCheck():
     """
-    Add Text here
+    Checks that TestON counters are consistent across all nodes.
+
+    Returns the tuple (onosCounters, consistent)
+    - onosCounters is the parsed json output of the counters command on all nodes
+    - consistent is main.TRUE if all "TestON" counters are consitent across all
+        nodes or main.FALSE
     """
     import json
     correctResults = main.TRUE
     # Get onos counters results
-    onosCounters = []
+    onosCountersRaw = []
     threads = []
     for i in range( main.numCtrls ):
         t = main.Thread( target=main.CLIs[i].counters,
@@ -17,25 +22,58 @@
         t.start()
     for t in threads:
         t.join()
-        onosCounters.append( t.result )
-    tmp = [ i == onosCounters[ 0 ] for i in onosCounters ]
+        onosCountersRaw.append( t.result )
+    onosCounters = []
+    for i in range( main.numCtrls ):
+        try:
+            onosCounters.append( json.loads( onosCountersRaw[i] ) )
+        except ( ValueError, TypeError ):
+            main.log.error( "Could not parse counters response from ONOS" +
+                            str( i + 1 ) )
+            main.log.warn( repr( onosCountersRaw[ i ] ) )
+            return main.FALSE
+
+    testCounters = {}
+    # make a list of all the "TestON-*" counters in ONOS
+    # lookes like a dict whose keys are the name of the ONOS node and values
+    # are a list of the counters. I.E.
+    # { "ONOS1": [ {"name":"TestON-inMemory","value":56},
+    #              {"name":"TestON-Partitions","value":56} ]
+    # }
+    # NOTE: There is an assumtion that all nodes are active
+    #        based on the above for loops
+    for controller in enumerate( onosCounters ):
+        for dbType in controller[1]:
+            for dbName, items in dbType.iteritems():
+                for item in items:
+                    if 'TestON' in item['name']:
+                        node = 'ONOS' + str( controller[0] + 1 )
+                        try:
+                            testCounters[node].append( item )
+                        except KeyError:
+                            testCounters[node] = [ item ]
+    # compare the counters on each node
+    tmp = [ v == testCounters['ONOS1'] for k, v in testCounters.iteritems() ]
     if all( tmp ):
         consistent = main.TRUE
     else:
         consistent = main.FALSE
-        main.log.error( "ONOS nodes have different values for counters" )
-        for node in onosCounters:
-            main.log.debug( node )
+        main.log.error( "ONOS nodes have different values for counters:\n" +
+                        testCounters )
+    return ( onosCounters, consistent )
 
+def counterCheck( counterName, counterValue ):
+    """
+    Checks that TestON counters are consistent across all nodes and that
+    specified counter is in ONOS with the given value
+    """
+    import json
+    correctResults = main.TRUE
+    # Get onos counters results and consistentCheck
+    onosCounters, consistent = main.Counters.consistentCheck()
     # Check for correct values
     for i in range( main.numCtrls ):
-        try:
-            current = json.loads( onosCounters[i] )
-        except ( ValueError, TypeError ):
-            main.log.error( "Could not parse counters response from ONOS" +
-                            str( i + 1 ) )
-            main.log.warn( repr( onosCounters[ i ] ) )
-            return main.FALSE
+        current = onosCounters[i]
         onosValue = None
         try:
             for database in current:
diff --git a/TestON/tests/HAminorityRestart/dependencies/onos-gen-partitions b/TestON/tests/HAminorityRestart/dependencies/onos-gen-partitions
new file mode 100755
index 0000000..bf9a77b
--- /dev/null
+++ b/TestON/tests/HAminorityRestart/dependencies/onos-gen-partitions
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+'''
+  Generate the partitions json file from the $OC* environment variables
+
+  Usage: onos-gen-partitions [output file]
+  If output file is not provided, the json is written to stdout.
+'''
+
+from os import environ
+from collections import deque, OrderedDict
+import re
+import json
+import sys
+
+convert = lambda text: int(text) if text.isdigit() else text.lower()
+alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
+
+def get_OC_vars():
+  vars = []
+  for var in environ:
+    if re.match(r"OC[0-9]+", var):
+      vars.append(var)
+  return sorted(vars, key=alphanum_key)
+
+def get_nodes(vars, port=9876):
+  node = lambda k: { 'id': k, 'ip': k, 'tcpPort': port }
+  return [ node(environ[v]) for v in vars ]
+
+def generate_permutations(nodes, k):
+  l = deque(nodes)
+  perms = {}
+  for i in range(1, len(nodes)+1):
+    perms['p%d' % i] = list(l)[:k]
+    l.rotate(-1)
+  return OrderedDict(sorted(perms.iteritems(), key=lambda (k, v): alphanum_key(k)))
+
+def generate_permutations2(nodes, k):
+  l = deque(nodes)
+  perms = {}
+  for i in range(1, (len(nodes) + 1) / 2 + 1):
+    perms['p%d' % i] = list(l)[:k]
+    l.rotate(-2)
+  return OrderedDict(sorted(perms.iteritems(), key=lambda (k, v): alphanum_key(k)))
+
+
+if __name__ == '__main__':
+  vars = get_OC_vars()
+  nodes = get_nodes(vars)
+  partitions = generate_permutations2(nodes, 3)
+  data = {
+           'nodes': nodes,
+           'partitions': partitions
+         }
+  output = json.dumps(data, indent=4)
+
+  if len(sys.argv) == 2:
+    filename = sys.argv[1]
+    with open(filename, 'w') as f:
+      f.write(output)
+  else:
+    print output