update my forked branch
diff --git a/TestON/drivers/common/cli/onosdriver.py b/TestON/drivers/common/cli/onosdriver.py
index ffed668..9734027 100644
--- a/TestON/drivers/common/cli/onosdriver.py
+++ b/TestON/drivers/common/cli/onosdriver.py
@@ -19,7 +19,6 @@
 import sys
 import time
 import pexpect
-import traceback
 import os.path
 from requests.models import Response
 sys.path.append( "../" )
@@ -32,6 +31,9 @@
         """
         Initialize client
         """
+        self.name = None
+        self.home = None
+        self.handle = None
         super( CLI, self ).__init__()
 
     def connect( self, **connectargs ):
@@ -41,11 +43,13 @@
         try:
             for key in connectargs:
                 vars( self )[ key ] = connectargs[ key ]
-            self.home = "~/ONOS"
+            self.home = "~/onos"
             for key in self.options:
                 if key == "home":
                     self.home = self.options[ 'home' ]
                     break
+            if self.home is None or self.home == "":
+                self.home = "~/onos"
 
             self.name = self.options[ 'name' ]
             self.handle = super( OnosDriver, self ).connect(
@@ -67,10 +71,8 @@
             main.log.error( self.name + ":     " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
-            main.log.info( self.name + ":" * 30 )
-            main.log.error( traceback.print_exc() )
-            main.log.info( ":" * 30 )
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
@@ -78,17 +80,21 @@
         """
         Called when Test is complete to disconnect the ONOS handle.
         """
-        response = ''
+        response = main.TRUE
         try:
-            self.handle.sendline( "" )
-            self.handle.expect( "\$" )
-            self.handle.sendline( "exit" )
-            self.handle.expect( "closed" )
+            if self.handle:
+                self.handle.sendline( "" )
+                self.handle.expect( "\$" )
+                self.handle.sendline( "exit" )
+                self.handle.expect( "closed" )
         except pexpect.EOF:
             main.log.error( self.name + ": EOF exception found" )
             main.log.error( self.name + ":     " + self.handle.before )
-        except:
-            main.log.error( self.name + ": Connection failed to the host" )
+        except ValueError:
+            main.log.exception( "Exception in disconnect of " + self.name )
+            response = main.TRUE
+        except Exception:
+            main.log.exception( self.name + ": Connection failed to the host" )
             response = main.FALSE
         return response
 
@@ -112,8 +118,8 @@
         except pexpect.EOF:
             main.log.error( self.name + ": EOF exception found" )
             main.log.error( self.name + ":    " + self.handle.before )
-        except:
-            main.log.error( "Failed to package ONOS" )
+        except Exception:
+            main.log.exception( "Failed to package ONOS" )
             main.cleanup()
             main.exit()
 
@@ -142,8 +148,8 @@
         except pexpect.EOF:
             main.log.error( self.name + ": EOF exception found" )
             main.log.error( self.name + ":    " + self.handle.before )
-        except:
-            main.log.error( "Failed to build ONOS" )
+        except Exception:
+            main.log.exception( "Failed to build ONOS" )
             main.cleanup()
             main.exit()
 
@@ -168,10 +174,11 @@
             self.handle.expect( "mvn clean install" )
             while True:
                 i = self.handle.expect( [
-                    'There\sis\sinsufficient\smemory\sfor\sthe\sJava\s\
-                            Runtime\sEnvironment\sto\scontinue',
+                    'There\sis\sinsufficient\smemory\sfor\sthe\sJava\s' +
+                    'Runtime\sEnvironment\sto\scontinue',
                     'BUILD\sFAILURE',
                     'BUILD\sSUCCESS',
+                    'onos\$',  #TODO: fix this to be more generic?
                     'ONOS\$',
                     pexpect.TIMEOUT ], mciTimeout )
                 if i == 0:
@@ -187,7 +194,7 @@
                     main.exit()
                 elif i == 2:
                     main.log.info( self.name + ": Build success!" )
-                elif i == 3:
+                elif i == 3 or i == 4:
                     main.log.info( self.name + ": Build complete" )
                     # Print the build time
                     for line in self.handle.before.splitlines():
@@ -196,7 +203,7 @@
                     self.handle.sendline( "" )
                     self.handle.expect( "\$", timeout=60 )
                     return main.TRUE
-                elif i == 4:
+                elif i == 5:
                     main.log.error(
                         self.name +
                         ": mvn clean install TIMEOUT!" )
@@ -204,8 +211,8 @@
                     main.cleanup()
                     main.exit()
                 else:
-                    main.log.error( self.name + ": unexpected response from \
-                            mvn clean install" )
+                    main.log.error( self.name + ": unexpected response from " +
+                                    "mvn clean install" )
                     # return main.FALSE
                     main.cleanup()
                     main.exit()
@@ -214,17 +221,19 @@
             main.log.error( self.name + ":     " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
-            main.log.info( self.name + ":" * 60 )
-            main.log.error( traceback.print_exc() )
-            main.log.info( ":" * 60 )
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
-    def gitPull( self, comp1="" ):
+    def gitPull( self, comp1="", fastForward=True ):
         """
         Assumes that "git pull" works without login
 
+        If the fastForward boolean is set to true, only git pulls that can
+        be fast forwarded will be performed. IE if you have not local commits
+        in your branch.
+
         This function will perform a git pull on the ONOS instance.
         If used as gitPull( "NODE" ) it will do git pull + NODE. This is
         for the purpose of pulling from other nodes if necessary.
@@ -239,12 +248,13 @@
             # main.log.info( self.name + ": Stopping ONOS" )
             # self.stop()
             self.handle.sendline( "cd " + self.home )
-            self.handle.expect( "ONOS\$" )
-            if comp1 == "":
-                self.handle.sendline( "git pull" )
-            else:
-                self.handle.sendline( "git pull " + comp1 )
-
+            self.handle.expect( self.home + "\$" )
+            cmd = "git pull"
+            if comp1 != "":
+                cmd += ' ' +  comp1
+            if fastForward:
+                cmd += ' ' + " --ff-only"
+            self.handle.sendline( cmd )
             i = self.handle.expect(
                 [
                     'fatal',
@@ -253,10 +263,11 @@
                     'Already up-to-date',
                     'Aborting',
                     'You\sare\snot\scurrently\son\sa\sbranch',
-                    'You\sasked\sme\sto\spull\swithout\stelling\sme\swhich\
-                            \sbranch\syou',
-                    'Pull\sis\snot\spossible\sbecause\syou\shave\sunmerged\
-                            \sfiles',
+                    'You asked me to pull without telling me which branch you',
+                    'Pull is not possible because you have unmerged files',
+                    'Please enter a commit message to explain why this merge',
+                    'Found a swap file by the name',
+                    'Please, commit your changes before you can merge.',
                     pexpect.TIMEOUT ],
                 timeout=300 )
             # debug
@@ -264,7 +275,11 @@
             # "git pull response: " +
             # str( self.handle.before ) + str( self.handle.after ) )
             if i == 0:
-                main.log.error( self.name + ": Git pull had some issue..." )
+                main.log.error( self.name + ": Git pull had some issue" )
+                output = self.handle.after
+                self.handle.expect( '\$' )
+                output += self.handle.before
+                main.log.warn( output )
                 return main.ERROR
             elif i == 1:
                 main.log.error(
@@ -275,7 +290,7 @@
                 main.log.info(
                     self.name +
                     ": Git Pull - pulling repository now" )
-                self.handle.expect( "ONOS\$", 120 )
+                self.handle.expect( self.home + "\$", 120 )
             # So that only when git pull is done, we do mvn clean compile
                 return main.TRUE
             elif i == 3:
@@ -284,29 +299,51 @@
             elif i == 4:
                 main.log.info(
                     self.name +
-                    ": Git Pull - Aborting...\
-                            Are there conflicting git files?" )
+                    ": Git Pull - Aborting..." +
+                    "Are there conflicting git files?" )
                 return main.ERROR
             elif i == 5:
                 main.log.info(
                     self.name +
-                    ": Git Pull - You are not currently\
-                            on a branch so git pull failed!" )
+                    ": Git Pull - You are not currently " +
+                    "on a branch so git pull failed!" )
                 return main.ERROR
             elif i == 6:
                 main.log.info(
                     self.name +
-                    ": Git Pull - You have not configured\
-                             an upstream branch to pull from\
-                             . Git pull failed!" )
+                    ": Git Pull - You have not configured an upstream " +
+                    "branch to pull from. Git pull failed!" )
                 return main.ERROR
             elif i == 7:
                 main.log.info(
                     self.name +
-                    ": Git Pull - Pull is not possible\
-                            because you have unmerged files." )
+                    ": Git Pull - Pull is not possible because " +
+                    "you have unmerged files." )
                 return main.ERROR
             elif i == 8:
+                # NOTE: abandoning test since we can't reliably handle this
+                #       there could be different default text editors and we
+                #       also don't know if we actually want to make the commit
+                main.log.error( "Git pull resulted in a merge commit message" +
+                                ". Exiting test!" )
+                main.cleanup()
+                main.exit()
+            elif i == 9:  # Merge commit message but swap file exists
+                main.log.error( "Git pull resulted in a merge commit message" +
+                                " but a swap file exists." )
+                try:
+                    self.handle.send( 'A' )  # Abort
+                    self.handle.expect( "\$" )
+                    return main.ERROR
+                except Exception:
+                    main.log.exception( "Couldn't exit editor prompt!")
+                    main.cleanup()
+                    main.exit()
+            elif i == 10:  # In the middle of a merge commit
+                main.log.error( "Git branch is in the middle of a merge. " )
+                main.log.warn( self.handle.before + self.handle.after )
+                return main.ERROR
+            elif i == 11:
                 main.log.error( self.name + ": Git Pull - TIMEOUT" )
                 main.log.error(
                     self.name + " Response was: " + str(
@@ -322,10 +359,8 @@
             main.log.error( self.name + ":     " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
-            main.log.info( self.name + ":" * 60 )
-            main.log.error( traceback.print_exc() )
-            main.log.info( ":" * 80 )
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
@@ -346,28 +381,24 @@
         """
         try:
             self.handle.sendline( "cd " + self.home )
-            self.handle.expect( "ONOS\$" )
-            main.log.info(
-                self.name +
-                ": Checking out git branch: " +
-                branch +
-                "..." )
+            self.handle.expect( self.home + "\$" )
+            main.log.info( self.name +
+                           ": Checking out git branch/ref: " + branch + "..." )
             cmd = "git checkout " + branch
             self.handle.sendline( cmd )
             self.handle.expect( cmd )
             i = self.handle.expect(
-                [
-                    'fatal',
-                    'Username\sfor\s(.*):\s',
-                    'Already\son\s\'',
-                    'Switched\sto\sbranch\s\'' +
-                    str( branch ),
-                    pexpect.TIMEOUT,
-                    'error: Your local changes to the following files\
-                            would be overwritten by checkout:',
-                    'error: you need to resolve your current index first' ],
+                [ 'fatal',
+                  'Username for (.*): ',
+                  'Already on \'',
+                  'Switched to branch \'' + str( branch ),
+                  pexpect.TIMEOUT,
+                  'error: Your local changes to the following files' +
+                  'would be overwritten by checkout:',
+                  'error: you need to resolve your current index first',
+                  "You are in 'detached HEAD' state.",
+                  "HEAD is now at " ],
                 timeout=60 )
-
             if i == 0:
                 main.log.error(
                     self.name +
@@ -380,55 +411,66 @@
                     ": Git checkout asking for username." +
                     " Please configure your local git repository to be able " +
                     "to access your remote repository passwordlessly" )
+                # TODO add support for authenticating
                 return main.ERROR
             elif i == 2:
                 main.log.info(
                     self.name +
-                    ": Git Checkout %s : Already on this branch" %
-                    branch )
-                self.handle.expect( "ONOS\$" )
+                    ": Git Checkout %s : Already on this branch" % branch )
+                self.handle.expect( self.home + "\$" )
                 # main.log.info( "DEBUG: after checkout cmd = "+
                 # self.handle.before )
                 return main.TRUE
             elif i == 3:
                 main.log.info(
                     self.name +
-                    ": Git checkout %s - Switched to this branch" %
-                    branch )
-                self.handle.expect( "ONOS\$" )
+                    ": Git checkout %s - Switched to this branch" % branch )
+                self.handle.expect( self.home + "\$" )
                 # main.log.info( "DEBUG: after checkout cmd = "+
                 # self.handle.before )
                 return main.TRUE
             elif i == 4:
                 main.log.error( self.name + ": Git Checkout- TIMEOUT" )
                 main.log.error(
-                    self.name + " Response was: " + str(
-                        self.handle.before ) )
+                    self.name + " Response was: " + str( self.handle.before ) )
                 return main.ERROR
             elif i == 5:
                 self.handle.expect( "Aborting" )
                 main.log.error(
                     self.name +
                     ": Git checkout error: \n" +
-                    "Your local changes to the following\
-                            files would be overwritten by checkout:" +
-                    str(
-                        self.handle.before ) )
-                self.handle.expect( "ONOS\$" )
+                    "Your local changes to the following files would" +
+                    " be overwritten by checkout:" +
+                    str( self.handle.before ) )
+                self.handle.expect( self.home + "\$" )
                 return main.ERROR
             elif i == 6:
-                main.log.error( self.name +
-                                ": Git checkout error: \n" +
-                                "You need to resolve your\
-                                        current index first:" +
-                                str( self.handle.before ) )
-                self.handle.expect( "ONOS\$" )
+                main.log.error(
+                    self.name +
+                    ": Git checkout error: \n" +
+                    "You need to resolve your current index first:" +
+                    str( self.handle.before ) )
+                self.handle.expect( self.home + "\$" )
                 return main.ERROR
+            elif i == 7:
+                main.log.info(
+                    self.name +
+                    ": Git checkout " + str( branch ) +
+                    " - You are in 'detached HEAD' state. HEAD is now at " +
+                    str( branch ) )
+                self.handle.expect( self.home + "\$" )
+                return main.TRUE
+            elif i == 8:  # Already in detached HEAD on the specified commit
+                main.log.info(
+                    self.name +
+                    ": Git Checkout %s : Already on commit" % branch )
+                self.handle.expect( self.home + "\$" )
+                return main.TRUE
             else:
                 main.log.error(
                     self.name +
-                    ": Git Checkout - Unexpected response,\
-                            check for pull errors" )
+                    ": Git Checkout - Unexpected response, " +
+                    "check for pull errors" )
                 main.log.error( self.name + ":     " + self.handle.before )
                 return main.ERROR
 
@@ -437,10 +479,8 @@
             main.log.error( self.name + ":     " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
-            main.log.info( self.name + ":" * 60 )
-            main.log.error( traceback.print_exc() )
-            main.log.info( ":" * 80 )
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
@@ -462,8 +502,8 @@
 
     def getVersion( self, report=False ):
         """
-        Writes the COMMIT number to the report to be parsed\
-                by Jenkins data collecter.
+        Writes the COMMIT number to the report to be parsed
+                by Jenkins data collector.
         """
         try:
             self.handle.sendline( "" )
@@ -471,8 +511,8 @@
             self.handle.sendline(
                 "cd " +
                 self.home +
-                "; git log -1 --pretty=fuller --decorate=short | grep -A 6\
-                        \"commit\" --color=never" )
+                "; git log -1 --pretty=fuller --decorate=short | grep -A 6 " +
+                " \"commit\" --color=never" )
             # NOTE: for some reason there are backspaces inserted in this
             # phrase when run from Jenkins on some tests
             self.handle.expect( "never" )
@@ -485,13 +525,18 @@
             for line in lines:
                 print line
             if report:
+                main.log.wiki( "<blockquote>" )
                 for line in lines[ 2:-1 ]:
                     # Bracket replacement is for Wiki-compliant
                     # formatting. '<' or '>' are interpreted
                     # as xml specific tags that cause errors
                     line = line.replace( "<", "[" )
                     line = line.replace( ">", "]" )
-                    main.log.report( "\t" + line )
+                    #main.log.wiki( "\t" + line )
+                    main.log.wiki( line + "<br /> " )
+                    main.log.summary( line )
+                main.log.wiki( "</blockquote>" )
+                main.log.summary("\n")
             return lines[ 2 ]
         except pexpect.EOF:
             main.log.error( self.name + ": EOF exception found" )
@@ -503,15 +548,13 @@
             main.log.error( self.name + ":     " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
-            main.log.info( self.name + ":" * 60 )
-            main.log.error( traceback.print_exc() )
-            main.log.info( ":" * 80 )
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
     def createCellFile( self, benchIp, fileName, mnIpAddrs,
-                         extraFeatureString, *onosIpAddrs ):
+                        appString, *onosIpAddrs ):
         """
         Creates a cell file based on arguments
         Required:
@@ -535,12 +578,11 @@
         # Create the cell file in the directory for writing ( w+ )
         cellFile = open( tempDirectory + fileName, 'w+' )
 
-        # Feature string is hardcoded environment variables
+        # App string is hardcoded environment variables
         # That you may wish to use by default on startup.
-        # Note that you  may not want certain features listed
+        # Note that you  may not want certain apps listed
         # on here.
-        coreFeatureString = "export ONOS_FEATURES=webconsole,onos-api," +\
-            "onos-cli,onos-openflow," + extraFeatureString
+        appString = "export ONOS_APPS=" + appString
         mnString = "export OCN="
         onosString = "export OC"
         tempCount = 1
@@ -569,7 +611,7 @@
                 tempCount = tempCount + 1
 
             cellFile.write( mnString + "\"" + mnIpAddrs + "\"" + "\n" )
-            cellFile.write( coreFeatureString + "\n" )
+            cellFile.write( appString + "\n" )
             cellFile.close()
 
             # We use os.system to send the command to TestON cluster
@@ -588,10 +630,8 @@
             main.log.error( self.name + ":     " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
-            main.log.info( self.name + ":::::::::" )
-            main.log.error( traceback.print_exc() )
-            main.log.info( ":::::::" )
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
@@ -609,12 +649,12 @@
                 # Expect the cellname in the ONOSCELL variable.
                 # Note that this variable name is subject to change
                 #   and that this driver will have to change accordingly
-                self.handle.expect( "ONOS_CELL=" + str( cellname ) )
+                self.handle.expect(str(cellname))
                 handleBefore = self.handle.before
                 handleAfter = self.handle.after
                 # Get the rest of the handle
-                self.handle.sendline( "" )
-                self.handle.expect( "\$" )
+                self.handle.sendline("")
+                self.handle.expect("\$")
                 handleMore = self.handle.before
 
                 main.log.info( "Cell call returned: " + handleBefore +
@@ -627,10 +667,8 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
-            main.log.info( self.name + " ::::::" )
-            main.log.error( traceback.print_exc() )
-            main.log.info( self.name + " ::::::" )
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
@@ -657,15 +695,55 @@
                            handleAfter + handleMore )
 
             return main.TRUE
-        except pexpect.EOF:
-            main.log.error( self.name + ": EOF exception found" )
+        except pexpect.ExceptionPexpect as e:
+            main.log.error( self.name + ": Pexpect exception found of type " +
+                            str( type( e ) ) )
+            main.log.error ( e.get_trace() )
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
-            main.log.info( self.name + " ::::::" )
-            main.log.error( traceback.print_exc() )
-            main.log.info( self.name + " ::::::" )
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
+            main.cleanup()
+            main.exit()
+
+    def onosCfgSet( self, ONOSIp, configName, configParam ):
+        """
+        Uses 'onos <node-ip> cfg set' to change a parameter value of an
+        application. 
+        
+        ex)
+            onos 10.0.0.1 cfg set org.onosproject.myapp appSetting 1
+
+        ONOSIp = '10.0.0.1'
+        configName = 'org.onosproject.myapp'
+        configParam = 'appSetting 1'
+
+        """
+        try:
+            cfgStr = ( "onos "+str(ONOSIp)+" cfg set "+
+                       str(configName) + " " +
+                       str(configParam)
+                     )
+
+            self.handle.sendline( "" )
+            self.handle.expect( "\$" )
+            self.handle.sendline( cfgStr )
+            self.handle.expect( "\$" )
+        
+            # TODO: Add meaningful assertion
+            
+            return main.TRUE
+
+        except pexpect.ExceptionPexpect as e:
+            main.log.error( self.name + ": Pexpect exception found of type " +
+                            str( type( e ) ) )
+            main.log.error ( e.get_trace() )
+            main.log.error( self.name + ":    " + self.handle.before )
+            main.cleanup()
+            main.exit()
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
@@ -723,10 +801,8 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
-            main.log.info( self.name + " ::::::" )
-            main.log.error( traceback.print_exc() )
-            main.log.info( self.name + " ::::::" )
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
@@ -778,10 +854,8 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
-            main.log.info( self.name + " ::::::" )
-            main.log.error( traceback.print_exc() )
-            main.log.info( self.name + " ::::::" )
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
@@ -816,10 +890,8 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
-            main.log.info( self.name + " ::::::" )
-            main.log.error( traceback.print_exc() )
-            main.log.info( self.name + " ::::::" )
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
@@ -835,6 +907,7 @@
                                   " stop" )
             i = self.handle.expect( [
                 "stop/waiting",
+                "Could not resolve hostname",
                 "Unknown\sinstance",
                 pexpect.TIMEOUT ], timeout=60 )
 
@@ -842,9 +915,12 @@
                 main.log.info( "ONOS service stopped" )
                 return main.TRUE
             elif i == 1:
-                main.log.info( "Unknown ONOS instance specified: " +
+                main.log.info( "onosStop() Unknown ONOS instance specified: " +
                                str( nodeIp ) )
                 return main.FALSE
+            elif i == 2:
+                main.log.warn( "ONOS wasn't running" )
+                return main.TRUE
             else:
                 main.log.error( "ONOS service failed to stop" )
                 return main.FALSE
@@ -854,10 +930,8 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
-            main.log.info( self.name + " ::::::" )
-            main.log.error( traceback.print_exc() )
-            main.log.info( self.name + " ::::::" )
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
@@ -869,7 +943,7 @@
         """
         try:
             self.handle.sendline( "" )
-            self.handle.expect( "\$" )
+            self.handle.expect( "\$", timeout=60 )
             self.handle.sendline( "onos-uninstall " + str( nodeIp ) )
             self.handle.expect( "\$" )
 
@@ -878,15 +952,16 @@
             # onos-uninstall command does not return any text
             return main.TRUE
 
+        except pexpect.TIMEOUT:
+            main.log.exception( self.name + ": Timeout in onosUninstall" )
+            return main.FALSE
         except pexpect.EOF:
             main.log.error( self.name + ": EOF exception found" )
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
-            main.log.info( self.name + " ::::::" )
-            main.log.error( traceback.print_exc() )
-            main.log.info( self.name + " ::::::" )
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
@@ -916,10 +991,8 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
-            main.log.info( self.name + " ::::::" )
-            main.log.error( traceback.print_exc() )
-            main.log.info( self.name + " ::::::" )
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
@@ -954,7 +1027,7 @@
                     " not configured" )
                 return main.FALSE
             else:
-                main.log.info( "ONOS instasnce was not killed" )
+                main.log.info( "ONOS instance was not killed" )
                 return main.FALSE
 
         except pexpect.EOF:
@@ -962,10 +1035,8 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
-            main.log.info( self.name + " ::::::" )
-            main.log.error( traceback.print_exc() )
-            main.log.info( self.name + " ::::::" )
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
@@ -990,8 +1061,8 @@
                                         timeout=120 )
                 if i == 1:
                     return main.FALSE
-            self.handle.sendline( "" )
-            self.handle.expect( "\$" )
+            #self.handle.sendline( "" )
+            #self.handle.expect( "\$" )
             return main.TRUE
 
         except pexpect.EOF:
@@ -999,10 +1070,8 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
-            main.log.info( self.name + " ::::::" )
-            main.log.error( traceback.print_exc() )
-            main.log.info( self.name + " ::::::" )
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
@@ -1038,26 +1107,23 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
-            main.log.info( self.name + " ::::::" )
-            main.log.error( traceback.print_exc() )
-            main.log.info( self.name + " ::::::" )
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
-    def isup( self, node="", onosWaitStartTimeout=120 ):
+    def isup(self, node = "", timeout = 120):
         """
         Run's onos-wait-for-start which only returns once ONOS is at run
-        level 100( ready for use )
+        level 100(ready for use)
 
         Returns: main.TRUE if ONOS is running and main.FALSE on timeout
         """
         try:
-            self.handle.sendline( "onos-wait-for-start " + node )
-            self.handle.expect( "onos-wait-for-start" )
+            self.handle.sendline("onos-wait-for-start " + node )
+            self.handle.expect("onos-wait-for-start")
             # NOTE: this timeout is arbitrary"
-            i = self.handle.expect( [ "\$", pexpect.TIMEOUT ],
-                    onosWaitStartTimeout )
+            i = self.handle.expect(["\$", pexpect.TIMEOUT], timeout)
             if i == 0:
                 main.log.info( self.name + ": " + node + " is up" )
                 return main.TRUE
@@ -1073,10 +1139,8 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
-            main.log.info( self.name + " ::::::" )
-            main.log.error( traceback.print_exc() )
-            main.log.info( self.name + " ::::::" )
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
@@ -1137,58 +1201,31 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
-            main.log.info( self.name + " ::::::" )
-            main.log.error( traceback.print_exc() )
-            main.log.info( self.name + " ::::::" )
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
     def getTopology( self, topologyOutput ):
         """
-        parses the onos:topology output
-        Returns: a topology dict populated by the key values found in
-                 the cli command.
+        Definition:
+            Loads a json topology output
+        Return:
+            topology = current ONOS topology
         """
+        import json
         try:
-            # call the cli to get the topology summary
-            # cmdstr = "onos:topology"
-            # cliResult = self.onosCli( ip, cmdstr )
-            # print "cli_result = ", cliResult
-
-            # Parse the output
-            topology = {}
-            # for line in cliResult.split( "\n" ):
-            for line in topologyOutput.splitlines():
-                if not line.startswith( "time=" ):
-                    continue
-                # else
-                # print line
-                for var in line.split( "," ):
-                    # print "'"+var+"'"
-                    # print "'"+var.strip()+"'"
-                    key, value = var.strip().split( "=" )
-                    topology[ key ] = value
-            # print "topology = ", topology
-            # devices = topology.get( 'devices', False )
-            # print "devices = ", devices
-            # links = topology.get( 'links', False )
-            # print "links = ", links
-            # SCCs = topology.get( 'SCC(s)', False )
-            # print "SCCs = ", SCCs
-            # paths = topology.get( 'paths', False )
-            # print "paths = ", paths
-
+            # either onos:topology or 'topology' will work in CLI
+            topology = json.loads(topologyOutput)
+            print topology
             return topology
         except pexpect.EOF:
             main.log.error( self.name + ": EOF exception found" )
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
-            main.log.info( self.name + " ::::::" )
-            main.log.error( traceback.print_exc() )
-            main.log.info( self.name + " ::::::" )
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
@@ -1199,21 +1236,21 @@
             numolink,
             logLevel="info" ):
         """
-        Checks the number of swithes & links that ONOS sees against the
+        Checks the number of switches & links that ONOS sees against the
         supplied values. By default this will report to main.log, but the
-        log level can be specifid.
+        log level can be specific.
 
         Params: ip = ip used for the onos cli
                 numoswitch = expected number of switches
-                numlink = expected number of links
+                numolink = expected number of links
                 logLevel = level to log to.
                 Currently accepts 'info', 'warn' and 'report'
 
 
         logLevel can
 
-        Returns: main.TRUE if the number of switchs and links are correct,
-                 main.FALSE if the numer of switches and links is incorrect,
+        Returns: main.TRUE if the number of switches and links are correct,
+                 main.FALSE if the number of switches and links is incorrect,
                  and main.ERROR otherwise
         """
         try:
@@ -1222,27 +1259,27 @@
                 return main.ERROR
             output = ""
             # Is the number of switches is what we expected
-            devices = topology.get( 'devices', False )
-            links = topology.get( 'links', False )
+            devices = topology.get( 'deviceCount', False )
+            links = topology.get( 'linkCount', False )
             if not devices or not links:
                 return main.ERROR
             switchCheck = ( int( devices ) == int( numoswitch ) )
             # Is the number of links is what we expected
             linkCheck = ( int( links ) == int( numolink ) )
-            if ( switchCheck and linkCheck ):
+            if switchCheck and linkCheck:
                 # We expected the correct numbers
                 output = output + "The number of links and switches match "\
                     + "what was expected"
                 result = main.TRUE
             else:
                 output = output + \
-                    "The number of links and switches does not match\
-                    what was expected"
+                    "The number of links and switches does not match " + \
+                    "what was expected"
                 result = main.FALSE
-            output = output + "\n ONOS sees %i devices (%i expected)\
-                     and %i links (%i expected)" %\
-                     ( int( devices ), int( numoswitch ),
-                       int( links ), int( numolink ) )
+            output = output + "\n ONOS sees %i devices" % int( devices )
+            output = output + " (%i expected) " % int( numoswitch )
+            output = output + "and %i links " % int( links )
+            output = output + "(%i expected)" % int( numolink )
             if logLevel == "report":
                 main.log.report( output )
             elif logLevel == "warn":
@@ -1255,10 +1292,8 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
-            main.log.info( self.name + " ::::::" )
-            main.log.error( traceback.print_exc() )
-            main.log.info( self.name + " ::::::" )
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
@@ -1271,31 +1306,41 @@
             * interface: interface to capture
             * dir: directory/filename to store pcap
         """
-        self.handle.sendline( "" )
-        self.handle.expect( "\$" )
+        try:
+            self.handle.sendline( "" )
+            self.handle.expect( "\$" )
 
-        self.handle.sendline( "tshark -i " + str( interface ) +
-                              " -t e -w " + str( dirFile ) + " &" )
-        self.handle.sendline( "\r" )
-        self.handle.expect( "Capturing on" )
-        self.handle.sendline( "\r" )
-        self.handle.expect( "\$" )
+            self.handle.sendline( "tshark -i " + str( interface ) +
+                                  " -t e -w " + str( dirFile ) + " &" )
+            self.handle.sendline( "\r" )
+            self.handle.expect( "Capturing on" )
+            self.handle.sendline( "\r" )
+            self.handle.expect( "\$" )
 
-        main.log.info( "Tshark started capturing files on " +
-                       str( interface ) + " and saving to directory: " +
-                       str( dirFile ) )
+            main.log.info( "Tshark started capturing files on " +
+                           str( interface ) + " and saving to directory: " +
+                           str( dirFile ) )
+        except pexpect.EOF:
+            main.log.error( self.name + ": EOF exception found" )
+            main.log.error( self.name + ":    " + self.handle.before )
+            main.cleanup()
+            main.exit()
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
+            main.cleanup()
+            main.exit()
 
     def runOnosTopoCfg( self, instanceName, jsonFile ):
         """
          On ONOS bench, run this command:
-         ./~/ONOS/tools/test/bin/onos-topo-cfg $OC1 filename
+         {ONOS_HOME}/tools/test/bin/onos-topo-cfg $OC1 filename
          which starts the rest and copies
          the json file to the onos instance
         """
         try:
             self.handle.sendline( "" )
             self.handle.expect( "\$" )
-            self.handle.sendline( "cd ~/ONOS/tools/test/bin" )
+            self.handle.sendline( "cd " + self.home + "/tools/test/bin" )
             self.handle.expect( "/bin$" )
             cmd = "./onos-topo-cfg " + instanceName + " " + jsonFile
             print "cmd = ", cmd
@@ -1304,48 +1349,82 @@
             self.handle.sendline( "cd ~" )
             self.handle.expect( "\$" )
             return main.TRUE
-        except:
-            return main.FALSE
+        except pexpect.EOF:
+            main.log.error( self.name + ": EOF exception found" )
+            main.log.error( self.name + ":    " + self.handle.before )
+            main.cleanup()
+            main.exit()
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
+            main.cleanup()
+            main.exit()
 
-    def tsharkGrep( self, grep, directory, interface='eth0' ):
+    def tsharkGrep( self, grep, directory, interface='eth0', grepOptions='' ):
         """
         Required:
             * grep string
             * directory to store results
         Optional:
             * interface - default: eth0
+            * grepOptions - options for grep 
         Description:
             Uses tshark command to grep specific group of packets
             and stores the results to specified directory.
             The timestamp is hardcoded to be in epoch
         """
-        self.handle.sendline( "" )
-        self.handle.expect( "\$" )
-        self.handle.sendline( "" )
-        self.handle.sendline(
-            "tshark -i " +
-            str( interface ) +
-            " -t e | grep --line-buffered \"" +
-            str(grep) +
-            "\" >" +
-            directory +
-            " &" )
-        self.handle.sendline( "\r" )
-        self.handle.expect( "Capturing on" )
-        self.handle.sendline( "\r" )
-        self.handle.expect( "\$" )
+        try:
+            self.handle.sendline( "" )
+            self.handle.expect( "\$" )
+            self.handle.sendline( "" )
+            if grepOptions:
+                grepStr = "grep "+str(grepOptions)
+            else:
+                grepStr = "grep"
+            
+            self.handle.sendline(
+                "tshark -i " +
+                str( interface ) +
+                " -t e | " +
+                grepStr + " --line-buffered \"" +
+                str(grep) +
+                "\" >" +
+                directory +
+                " &" )
+            self.handle.sendline( "\r" )
+            self.handle.expect( "Capturing on" )
+            self.handle.sendline( "\r" )
+            self.handle.expect( "\$" )
+        except pexpect.EOF:
+            main.log.error( self.name + ": EOF exception found" )
+            main.log.error( self.name + ":    " + self.handle.before )
+            main.cleanup()
+            main.exit()
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
+            main.cleanup()
+            main.exit()
 
     def tsharkStop( self ):
         """
         Removes wireshark files from /tmp and kills all tshark processes
         """
         # Remove all pcap from previous captures
-        self.execute( cmd="sudo rm /tmp/wireshark*" )
-        self.handle.sendline( "" )
-        self.handle.sendline( "sudo kill -9 `ps -ef | grep \"tshark -i\" |" +
-                              " grep -v grep | awk '{print $2}'`" )
-        self.handle.sendline( "" )
-        main.log.info( "Tshark stopped" )
+        try:
+            self.execute( cmd="sudo rm /tmp/wireshark*" )
+            self.handle.sendline( "" )
+            self.handle.sendline( "sudo kill -9 `ps -ef | grep \"tshark -i\"" +
+                                  " | grep -v grep | awk '{print $2}'`" )
+            self.handle.sendline( "" )
+            main.log.info( "Tshark stopped" )
+        except pexpect.EOF:
+            main.log.error( self.name + ": EOF exception found" )
+            main.log.error( self.name + ":    " + self.handle.before )
+            main.cleanup()
+            main.exit()
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
+            main.cleanup()
+            main.exit()
 
     def ptpd( self, args ):
         """
@@ -1380,15 +1459,13 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
-            main.log.info( self.name + " ::::::" )
-            main.log.error( traceback.print_exc() )
-            main.log.info( self.name + " ::::::" )
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
 
     def cpLogsToDir( self, logToCopy,
-                       destDir, copyFileName="" ):
+                     destDir, copyFileName="" ):
         """
         Copies logs to a desired directory.
         Current implementation of ONOS deletes its karaf
@@ -1420,13 +1497,9 @@
                 destDir += "/"
 
             if copyFileName:
-                self.handle.sendline(
-                    "cp " +
-                    str( logToCopy ) +
-                    " " +
-                    str( destDir ) +
-                    str( copyFileName ) +
-                    localtime )
+                self.handle.sendline( "cp " + str( logToCopy ) + " " +
+                                      str( destDir ) + str( copyFileName ) +
+                                      localtime )
                 self.handle.expect( "cp" )
                 self.handle.expect( "\$" )
             else:
@@ -1441,11 +1514,8 @@
             main.log.error( "Copying files failed" )
             main.log.error( self.name + ": EOF exception found" )
             main.log.error( self.name + ":    " + self.handle.before )
-        except:
-            main.log.error( "Copying files failed" )
-            main.log.info( self.name + " ::::::" )
-            main.log.error( traceback.print_exc() )
-            main.log.info( self.name + " ::::::" )
+        except Exception:
+            main.log.exception( "Copying files failed" )
 
     def checkLogs( self, onosIp ):
         """
@@ -1463,11 +1533,10 @@
             main.log.error( "Lost ssh connection" )
             main.log.error( self.name + ": EOF exception found" )
             main.log.error( self.name + ":    " + self.handle.before )
-        except:
-            main.log.error( "Some error in check_logs:" )
-            main.log.info( self.name + " ::::::" )
-            main.log.error( traceback.print_exc() )
-            main.log.info( self.name + " ::::::" )
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
+            main.cleanup()
+            main.exit()
 
     def onosStatus( self, node="" ):
         """
@@ -1488,8 +1557,6 @@
                 return main.TRUE
             elif i == 1:
                 main.log.info( "ONOS is stopped" )
-                return main.FALSE
-            else:
                 main.log.error( "ONOS service failed to check the status" )
                 main.cleanup()
                 main.exit()
@@ -1498,9 +1565,503 @@
             main.log.error( self.name + ":    " + self.handle.before )
             main.cleanup()
             main.exit()
-        except:
-            main.log.info( self.name + " ::::::" )
-            main.log.error( traceback.print_exc() )
-            main.log.info( self.name + " ::::::" )
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
+
+    def setIpTables( self, ip, port='', action='add', packet_type='',
+                     direction='INPUT', rule='DROP', states=True ):
+        """
+        Description:
+            add or remove iptables rule to DROP (default) packets from
+            specific IP and PORT
+        Usage:
+        * specify action ('add' or 'remove')
+          when removing, pass in the same argument as you would add. It will
+          delete that specific rule.
+        * specify the ip to block
+        * specify the destination port to block (defaults to all ports)
+        * optional packet type to block (default tcp)
+        * optional iptables rule (default DROP)
+        * optional direction to block (default 'INPUT')
+        * States boolean toggles adding all supported tcp states to the
+          firewall rule
+        Returns:
+            main.TRUE on success or
+            main.FALSE if given invalid input or
+            main.ERROR if there is an error in response from iptables
+        WARNING:
+        * This function uses root privilege iptables command which may result
+          in unwanted network errors. USE WITH CAUTION
+        """
+        import time
+
+        # NOTE*********
+        #   The strict checking methods of this driver function is intentional
+        #   to discourage any misuse or error of iptables, which can cause
+        #   severe network errors
+        # *************
+
+        # NOTE: Sleep needed to give some time for rule to be added and
+        #       registered to the instance. If you are calling this function
+        #       multiple times this sleep will prevent any errors.
+        #       DO NOT REMOVE
+        # time.sleep( 5 )
+        try:
+            # input validation
+            action_type = action.lower()
+            rule = rule.upper()
+            direction = direction.upper()
+            if action_type != 'add' and action_type != 'remove':
+                main.log.error( "Invalid action type. Use 'add' or "
+                                "'remove' table rule" )
+                if rule != 'DROP' and rule != 'ACCEPT' and rule != 'LOG':
+                    # NOTE Currently only supports rules DROP, ACCEPT, and LOG
+                    main.log.error( "Invalid rule. Valid rules are 'DROP' or "
+                                    "'ACCEPT' or 'LOG' only." )
+                    if direction != 'INPUT' and direction != 'OUTPUT':
+                        # NOTE currently only supports rules INPUT and OUPTUT
+                        main.log.error( "Invalid rule. Valid directions are"
+                                        " 'OUTPUT' or 'INPUT'" )
+                        return main.FALSE
+                    return main.FALSE
+                return main.FALSE
+            if action_type == 'add':
+                # -A is the 'append' action of iptables
+                actionFlag = '-A'
+            elif action_type == 'remove':
+                # -D is the 'delete' rule of iptables
+                actionFlag = '-D'
+            self.handle.sendline( "" )
+            self.handle.expect( "\$" )
+            cmd = "sudo iptables " + actionFlag + " " +\
+                  direction +\
+                  " -s " + str( ip )
+                  # " -p " + str( packet_type ) +\
+            if packet_type:
+                cmd += " -p " + str( packet_type )
+            if port:
+                cmd += " --dport " + str( port )
+            if states:
+                cmd += " -m state --state="
+                #FIXME- Allow user to configure which states to block
+                cmd += "INVALID,ESTABLISHED,NEW,RELATED,UNTRACKED"
+            cmd += " -j " + str( rule )
+
+            self.handle.sendline( cmd )
+            self.handle.expect( "\$" )
+            main.log.warn( self.handle.before )
+
+            info_string = "On " + str( self.name )
+            info_string += " " + str( action_type )
+            info_string += " iptable rule [ "
+            info_string += " IP: " + str( ip )
+            info_string += " Port: " + str( port )
+            info_string += " Rule: " + str( rule )
+            info_string += " Direction: " + str( direction ) + " ]"
+            main.log.info( info_string )
+            return main.TRUE
+        except pexpect.TIMEOUT:
+            main.log.exception( self.name + ": Timeout exception in "
+                                "setIpTables function" )
+            return main.ERROR
+        except pexpect.EOF:
+            main.log.error( self.name + ": EOF exception found" )
+            main.log.error( self.name + ":    " + self.handle.before )
+            main.cleanup()
+            main.exit()
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
+            main.cleanup()
+            main.exit()
+
+    def detailed_status(self, log_filename):
+        """
+        This method is used by STS to check the status of the controller
+        Reports RUNNING, STARTING, STOPPED, FROZEN, ERROR (and reason)
+        """
+        import re
+        try:
+            self.handle.sendline( "" )
+            self.handle.expect( "\$" )
+            self.handle.sendline( "cd " + self.home )
+            self.handle.expect( "\$" )
+            self.handle.sendline( "service onos status" )
+            self.handle.expect( "\$" )
+            response = self.handle.before
+            if re.search( "onos start/running", response ):
+                # onos start/running, process 10457
+                return 'RUNNING'
+            # FIXME: Implement this case
+            # elif re.search( pattern, response ):
+            #      return 'STARTING'
+            elif re.search( "onos stop/", response ):
+                # onos stop/waiting
+                # FIXME handle this differently?:  onos stop/pre-stop
+                return 'STOPPED'
+            # FIXME: Implement this case
+            # elif re.search( pattern, response ):
+            #      return 'FROZEN'
+            else:
+                main.log.warn( self.name +
+                               " WARNING: status received unknown response" )
+                main.log.warn( response )
+                return 'ERROR', "Unknown response: %s" % response
+        except pexpect.TIMEOUT:
+            main.log.exception( self.name + ": Timeout exception in "
+                                "setIpTables function" )
+            return 'ERROR', "Pexpect Timeout"
+        except pexpect.EOF:
+            main.log.error( self.name + ": EOF exception found" )
+            main.log.error( self.name + ":    " + self.handle.before )
+            main.cleanup()
+            main.exit()
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
+            main.cleanup()
+            main.exit()
+
+    def createLinkGraphFile( self, benchIp, ONOSIpList, deviceCount):
+        '''
+            Create/formats the LinkGraph.cfg file based on arguments 
+                -only creates a linear topology and connects islands 
+                -evenly distributes devices 
+                -must be called by ONOSbench
+
+                ONOSIpList - list of all of the node IPs to be used 
+                
+                deviceCount - number of switches to be assigned 
+        '''
+        main.log.step("Creating link graph configuration file." )
+        linkGraphPath = self.home + "/tools/package/etc/linkGraph.cfg"
+        tempFile = "/tmp/linkGraph.cfg"        
+
+        linkGraph = open(tempFile, 'w+')
+        linkGraph.write("# NullLinkProvider topology description (config file).\n")
+        linkGraph.write("# The NodeId is only added if the destination is another node's device.\n")
+        linkGraph.write("# Bugs: Comments cannot be appended to a line to be read.\n")
+        
+        clusterCount = len(ONOSIpList)
+        
+        if type(deviceCount) is int or type(deviceCount) is str: 
+            deviceCount = int(deviceCount)
+            switchList = [0]*(clusterCount+1)
+            baselineSwitchCount = deviceCount/clusterCount
+        
+            for node in range(1, clusterCount + 1):
+                switchList[node] = baselineSwitchCount
+
+            for node in range(1, (deviceCount%clusterCount)+1):
+                switchList[node] += 1
+        
+        if type(deviceCount) is list:
+            main.log.info("Using provided device distribution")
+            switchList = [0]
+            for i in deviceCount:
+                switchList.append(int(i))
+
+        tempList = ['0']
+        tempList.extend(ONOSIpList)
+        ONOSIpList = tempList
+
+        myPort = 6
+        lastSwitch = 0
+        for node in range(1, clusterCount+1):
+            if switchList[node] == 0:
+                continue
+
+            linkGraph.write("graph " + ONOSIpList[node] + " {\n")
+            
+            if node > 1:
+                #connect to last device on previous node
+                line = ("\t0:5 -> " + str(lastSwitch) + ":6:" + lastIp + "\n")     #ONOSIpList[node-1]  
+                linkGraph.write(line)            
+               
+            lastSwitch = 0 
+            for switch in range (0, switchList[node]-1):    
+                line = ""
+                line = ("\t" + str(switch) + ":" + str(myPort))
+                line += " -- "
+                line += (str(switch+1) + ":" + str(myPort-1) + "\n")
+                linkGraph.write(line)
+                lastSwitch = switch+1 
+            lastIp = ONOSIpList[node]
+                
+            #lastSwitch += 1
+            if node < (clusterCount): 
+                #connect to first device on the next node
+                line = ("\t" + str(lastSwitch) + ":6 -> 0:5:" + ONOSIpList[node+1] + "\n")             
+                linkGraph.write(line)
+                
+            linkGraph.write("}\n")
+        linkGraph.close()
+
+        #SCP
+        os.system( "scp " + tempFile + " admin@" + benchIp + ":" + linkGraphPath)        
+        main.log.info("linkGraph.cfg creation complete")
+
+    def configNullDev( self, ONOSIpList, deviceCount, numPorts=10):
+        
+        '''
+            ONOSIpList = list of Ip addresses of nodes switches will be devided amongst 
+            deviceCount = number of switches to distribute, or list of values to use as custom distribution  
+            numPorts = number of ports per device. Defaults to 10 both in this function and in ONOS. Optional arg
+        '''
+
+        main.log.step("Configuring Null Device Provider" )
+        clusterCount = len(ONOSIpList)
+
+        try: 
+            
+            if type(deviceCount) is int or type(deviceCount) is str:
+                main.log.step("Creating device distribution")
+                deviceCount = int(deviceCount)
+                switchList = [0]*(clusterCount+1)
+                baselineSwitchCount = deviceCount/clusterCount
+
+                for node in range(1, clusterCount + 1):
+                    switchList[node] = baselineSwitchCount
+
+                for node in range(1, (deviceCount%clusterCount)+1):
+                    switchList[node] += 1
+                
+            if type(deviceCount) is list: 
+                main.log.info("Using provided device distribution") 
+                
+                if len(deviceCount) == clusterCount: 
+                    switchList = ['0']
+                    switchList.extend(deviceCount)
+                
+                if len(deviceCount) == (clusterCount + 1): 
+                    if deviceCount[0] == '0' or deviceCount[0] == 0: 
+                        switchList = deviceCount
+
+                assert len(switchList) == (clusterCount + 1)
+        
+        except AssertionError:
+            main.log.error( "Bad device/Ip list match") 
+        except TypeError:
+            main.log.exception( self.name + ": Object not as expected" )
+            return None
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
+            main.cleanup()
+            main.exit()
+
+
+        ONOSIp = [0]
+        ONOSIp.extend(ONOSIpList)
+ 
+        devicesString  = "devConfigs = "
+        for node in range(1, len(ONOSIp)):
+            devicesString += (ONOSIp[node] + ":" + str(switchList[node] ))
+            if node < clusterCount:
+                devicesString += (",")
+        
+        try: 
+            self.handle.sendline("onos $OC1 cfg set org.onosproject.provider.nil.device.impl.NullDeviceProvider devConfigs " + devicesString )
+            self.handle.expect(":~")
+            self.handle.sendline("onos $OC1 cfg set org.onosproject.provider.nil.device.impl.NullDeviceProvider numPorts " + str(numPorts) )
+            self.handle.expect(":~")
+
+            for i in range(10):
+                self.handle.sendline("onos $OC1 cfg get org.onosproject.provider.nil.device.impl.NullDeviceProvider")
+                self.handle.expect(":~")
+                verification = self.handle.before
+                if (" value=" + str(numPorts)) in verification and (" value=" + devicesString) in verification:
+                    break
+                else:
+                    time.sleep(1)
+
+            assert ("value=" + str(numPorts)) in verification and (" value=" + devicesString) in verification
+        
+        except AssertionError:
+            main.log.error("Incorrect Config settings: " + verification)
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
+            main.cleanup()
+            main.exit()
+
+    def configNullLink( self,fileName="/opt/onos/apache-karaf-3.0.3/etc/linkGraph.cfg", eventRate=0): 
+        '''
+                fileName default is currently the same as the default on ONOS, specify alternate file if 
+                you want to use a different topology file than linkGraph.cfg
+        '''
+
+        
+        try: 
+            self.handle.sendline("onos $OC1 cfg set org.onosproject.provider.nil.link.impl.NullLinkProvider eventRate " + str(eventRate)) 
+            self.handle.expect(":~")            
+            self.handle.sendline("onos $OC1 cfg set org.onosproject.provider.nil.link.impl.NullLinkProvider cfgFile " + fileName )
+            self.handle.expect(":~")
+               
+            for i in range(10): 
+                self.handle.sendline("onos $OC1 cfg get org.onosproject.provider.nil.link.impl.NullLinkProvider") 
+                self.handle.expect(":~")
+                verification = self.handle.before
+                if (" value=" + str(eventRate)) in verification and (" value=" + fileName) in verification: 
+                    break
+                else: 
+                    time.sleep(1)
+            
+            assert ("value=" + str(eventRate)) in verification and (" value=" + fileName) in verification
+            
+        except pexpect.EOF:
+            main.log.error( self.name + ": EOF exception found" )
+            main.log.error( self.name + ":    " + self.handle.before )
+            main.cleanup()
+            main.exit()
+        except AssertionError:
+            main.log.info("Settings did not post to ONOS")
+            main.log.error(varification)            
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
+            main.log.error(varification)
+            main.cleanup()
+            main.exit()
+
+
+    def getOnosIpFromEnv(self):
+
+        import string  
+
+        # returns a list of ip addresses for the onos nodes, will work with up to 7 nodes + OCN and OCI
+        # returns in format [ 'x', OC1 ip, OC2 i... ect. ... , ONN ip ]
+
+        self.handle.sendline("env| grep OC") 
+        self.handle.expect(":~")
+        rawOutput = self.handle.before
+        print rawOutput
+        print "-----------------------------"
+        print repr(rawOutput)
+        mpa = dict.fromkeys(range(32))
+        translated = rawOutput.translate(mpa)
+        print translated
+
+
+        # create list with only the lines that have the needed IPs 
+        unparsedIps = []
+
+        # remove preceeding or trailing lines
+        for line in rawOutput: 
+            if "OC" in line and "=" in line: 
+                unparsedIps.append(str(line)) 
+
+        # determine cluster size
+        clusterCount = 0
+        for line in unparsedIps:
+            line = str(line)
+            print line
+            temp = line.replace("OC","")
+            print("line index " + str(line.index("="))) 
+            OCindex = temp[0]
+            for i in range(0, 7):
+                if OCindex == str(i) and i > clusterCount:
+                    clusterCount == i
+                    print(clusterCount)
+        # create list to hold ips such that OC1 is at list[1] and OCN and OCI are at the end (in that order)
+        ONOSIps = ["x"] * (clusterCount + 3) 
+
+        # populate list 
+        for line in unparsedIps:
+            main.log.info(line)########## 
+            temp = str(line.replace("OC",""))
+            main.log.info(str(list(temp)))
+            OCindex = temp[0]
+            main.log.info(OCindex)############
+            if OCindex == "N":
+                ONOSIps[ clusterCount + 1 ] = temp.replace("N=","")
+    
+            if OCindex == "I":
+                ONOSIps[ clusterCount + 2 ] = temp.replace("I=","")
+
+            else:
+                ONOSIps[ int(OCindex) ] = temp.replace((OCindex + "=") ,"")
+
+        # validate 
+        for x in ONOSIps: 
+            if ONOSIps.index(x) != 0 and x == "x": 
+                main.log.error("ENV READ FAILURE, MISSING DATA: \n\n" + str(ONOSIps) + "\n\n") 
+
+        return ONOSIps
+
+        
+    def onosErrorLog(self, nodeIp): 
+
+        cmd = "onos-ssh " + nodeIp + " cat /opt/onos/log/karaf.log | grep WARN"
+        self.handle.sendline(cmd) 
+        self.handle.expect(":~")
+        before = (self.handle.before).splitlines() 
+    
+        warnings = []
+
+        for line in before: 
+            if "WARN" in line and "grep" not in line: 
+                warnings.append(line) 
+                main.warnings[main.warnings[0]+1] = line
+                main.warnings[0] += 1
+                if main.warnings[0] >= 10: 
+                    main.warnings[0] = 0 
+
+        cmd = "onos-ssh " + nodeIp + " cat /opt/onos/log/karaf.log | grep ERROR"
+        self.handle.sendline(cmd)
+        self.handle.expect(":~")
+        before = (self.handle.before).splitlines()
+
+        errors = []
+
+        for line in before:
+            if "ERROR" in line and "grep" not in line:
+                errors.append(line)
+                main.errors[main.errors[0]+1] = line
+                main.errors[0] += 1
+                if main.errors[0] >= 10:
+                    main.errors[0] = 0
+
+        cmd = "onos-ssh " + nodeIp + " cat /opt/onos/log/karaf.log | grep Exept"
+        self.handle.sendline(cmd)
+        self.handle.expect(":~")
+        before = (self.handle.before).splitlines()
+
+        exceptions = []
+
+        for line in before:
+            if "Except" in line and "grep" not in line:
+                exceptions.append(line)
+                main.exceptions[main.errors[0]+1] = line
+                main.exceptions[0] += 1
+                if main.exceptions[0] >= 10:
+                    main.exceptions[0] = 0
+
+
+
+        ################################################################
+
+        msg1 = "WARNINGS: \n"
+        for i in main.warnings: 
+            if type(i) is not int: 
+                msg1 += ( i + "\n")
+
+        msg2 = "ERRORS: \n"
+        for i in main.errors:
+            if type(i) is not int:
+                msg2 += ( i + "\n")
+
+        msg3 = "EXCEPTIONS: \n"
+        for i in main.exceptions: 
+            if type(i) is not int:
+                msg3 += ( i + "\n")
+
+        main.log.info("===============================================================\n") 
+        main.log.info( "Warnings: " + str(len(warnings))) 
+        main.log.info( "Errors: " + str(len(errors))) 
+        main.log.info( "Exceptions: " + str(len(exceptions)))
+        if len(warnings) > 0:
+            main.log.info(msg1)
+        if len(errors) > 0: 
+            main.log.info(msg2)
+        if len(exceptions) > 0: 
+            main.log.info(msg3)
+        main.log.info("===============================================================\n")
+