Update Cluster Driver

Change-Id: I8a3a57e19637ff210548e57d41178e6f194cf694
diff --git a/TestON/tests/dependencies/Cluster.py b/TestON/tests/dependencies/Cluster.py
index 01dc767..6b18b8b 100644
--- a/TestON/tests/dependencies/Cluster.py
+++ b/TestON/tests/dependencies/Cluster.py
@@ -27,33 +27,104 @@
     def __repr__( self ):
         #TODO use repr of cli's?
         controllers = []
+        runningNodes = []
         for ctrl in self.controllers:
             controllers.append( str( ctrl ) )
         return "%s[%s]" % ( self.name, ", ".join( controllers ) )
 
 
     def __init__( self, ctrlList=[], name="Cluster" ):
-        #assert isInstance( ctrlList, Controller ), "ctrlList should be a list of ONOS Controllers"
+        '''
+            controllers : All the nodes
+            runningNodes : Node that are specifically running from the test.
+                ie) When the test is testing different number of nodes on each
+                    run.
+            numCtrls : number of runningNodes
+            maxCtrls : number of controllers
+        '''
         self.controllers = ctrlList
+        self.runningNodes = ctrlList
+        self.numCtrls = len( self.runningNodes )
+        self.maxCtrls = len( self.controllers )
         self.name = str( name )
         self.iterator = iter( self.active() )
 
-    def getIps( self, activeOnly=False):
+    def getIps( self, activeOnly=False, allNode=False ):
+        """
+        Description:
+            get the list of the ip. Default to get ips of running nodes.
+        Required:
+            * activeOnly - True for getting ips of active nodes
+            * allNode - True for getting ips of all nodes
+        Returns:
+            Retruns ips of active nodes if activeOnly is True.
+            Returns ips of all nodes if allNode is True.
+        """
         ips = []
-        if activeOnly:
-            nodeList = self.active()
-        else:
+        if allNode:
             nodeList = self.controllers
+        else:
+            if activeOnly:
+                nodeList = self.active()
+            else:
+                nodeList = self.runningNodes
+
         for ctrl in nodeList:
             ips.append( ctrl.ipAddress )
+
         return ips
 
-    def active( self ):
+    def resetActive( self ):
         """
-        Return a list of active controllers in the cluster
+        Description:
+            reset the activeness of the runningNodes to be false
+        Required:
+        Returns:
         """
-        return [ ctrl for ctrl in self.controllers
+        for ctrl in self.runningNodes:
+            ctrl.active = False
+
+    def getRunningPos( self ):
+        """
+        Description:
+            get the position of the active running nodes.
+        Required:
+        Returns:
+            Retruns the list of the position of the active
+            running nodes.
+        """
+        return [ ctrl.pos for ctrl in self.runningNodes
+                 if ctrl.active ]
+
+    def setRunningNode( self, numCtrls ):
+        """
+        Description:
+            Set running nodes of n number of nodes.
+            It will create new list of runningNodes.
+            If numCtrls is a list, it will add the nodes of the
+            list.
+        Required:
+            * numCtrls - number of nodes to be set.
+        Returns:
+        """
+        self.runningNodes = []
+        for i in numCtrls if isinstance( numCtrls, list ) else range( numCtrls ) :
+            self.runningNodes.append( self.controllers[ i ] )
+        self.numCtrls = len( numCtrls ) if isinstance( numCtrls, list ) else numCtrls
+
+    def active( self, node=None ):
+        """
+        Description:
+            get the list/controller of the active controller.
+        Required:
+            * node - position of the node to get from the active controller.
+        Returns:
+            Return a list of active controllers in the cluster if node is None
+            if not, it will return the nth controller.
+        """
+        result = [ ctrl for ctrl in self.runningNodes
                       if ctrl.active ]
+        return result if node is None else result[ node % len( result ) ]
 
     def next( self ):
         """
@@ -80,24 +151,151 @@
         """
         self.iterator = iter( self.active() )
 
-    def install( self ):
+    def createCell( self, cellName, Mininet, useSSH, ips ):
         """
-        Install ONOS on all controller nodes in the cluster
+        Description:
+            create a new cell
+        Required:
+            * cellName - The name of the cell.
+            * Mininet - a mininet driver that will be used.
+            * useSSH - True for using ssh when creating a cell
+            * ips - ip(s) of the node(s).
+        Returns:
+        """
+        main.ONOSbench.createCellFile( main.ONOSbench.ip_address,
+                                       cellName,
+                                       Mininet if isinstance( Mininet, str ) else
+                                       Mininet.ip_address,
+                                       main.apps,
+                                       ips,
+                                       main.ONOScell.karafUser,
+                                       useSSH=useSSH )
+
+    def uninstall( self, uninstallMax ):
+        """
+        Description:
+            uninstalling onos
+        Required:
+            * uninstallMax - True for uninstalling max number of nodes
+            False for uninstalling the current running nodes.
+        Returns:
+            Returns main.TRUE if it successfully uninstalled.
+        """
+        onosUninstallResult = main.TRUE
+        for ctrl in self.controllers if uninstallMax else self.runningNodes:
+            onosUninstallResult = onosUninstallResult and \
+                                  main.ONOSbench.onosUninstall( nodeIp=ctrl.ipAddress )
+        return onosUninstallResult
+
+    def applyCell( self, cellName ):
+        """
+        Description:
+            apply the cell with cellName. It will also verify the
+            cell.
+        Required:
+            * cellName - The name of the cell.
+        Returns:
+            Returns main.TRUE if it successfully set and verify cell.
+        """
+        cellResult = main.ONOSbench.setCell( cellName )
+        verifyResult = main.ONOSbench.verifyCell()
+        return cellResult and verifyResult
+
+    def checkService( self ):
+        """
+        Description:
+            Checking if the onos service is up. If not, it will
+            start the onos service manually.
+        Required:
+        Returns:
+            Returns main.TRUE if it successfully checked
+        """
+        stopResult = main.TRUE
+        startResult = main.TRUE
+        onosIsUp = main.TRUE
+        i = 0
+        for ctrl in self.runningNodes:
+            onosIsUp = onosIsUp and main.ONOSbench.isup( ctrl.ipAddress )
+            if onosIsUp == main.TRUE:
+                main.log.report( "ONOS instance {0} is up and ready".format( i + 1 ) )
+            else:
+                main.log.report( "ONOS instance {0} may not be up, stop and ".format( i + 1 ) +
+                                 "start ONOS again " )
+                stopResult = stopResult and main.ONOSbench.onosStop( ctrl.ipAddress )
+                startResult = startResult and main.ONOSbench.onosStart( ctrl.ipAddress )
+                if not startResult or stopResult:
+                    main.log.report( "ONOS instance {0} did not start correctly.".format( i + 1 ) )
+            i += 1
+        return onosIsUp and stopResult and startResult
+
+    def kill( self, killMax, stopOnos ):
+        """
+        Description:
+            killing the onos. It will either kill the current runningnodes or
+            max number of the nodes.
+        Required:
+            * killRemoveMax - The boolean that will decide either to kill
+            only running nodes (False) or max number of nodes (True).
+            * stopOnos - If wish to stop onos before killing it. True for
+            enable stop , False for disable stop.
+        Returns:
+            Returns main.TRUE if successfully killing it.
         """
         result = main.TRUE
-        # FIXME: use the correct onosdriver function
-        # TODO: Use threads to install in parallel, maybe have an option for sequential installs
-        for ctrl in self.controllers:
-            result &= ctrl.installOnos( ctrl.ipAddress )
+        for ctrl in self.controllers if killMax else self.runningNodes:
+            if stopOnos:
+                result = result and main.ONOSbench.onosStop( ctrl.ipAddress )
+            result = result and main.ONOSbench.onosKill( ctrl.ipAddress )
+            ctrl.active = False
+        return result
+
+    def ssh( self ):
+        """
+        Description:
+            set up ssh to the onos
+        Required:
+        Returns:
+            Returns main.TRUE if it successfully setup the ssh to
+            the onos.
+        """
+        secureSshResult = main.TRUE
+        for ctrl in self.runningNodes:
+            secureSshResult = secureSshResult and main.ONOSbench.onosSecureSSH( node=ctrl.ipAddress )
+        return secureSshResult
+
+    def install( self, installMax=True ):
+        """
+        Description:
+            Installing onos.
+        Required:
+            * installMax - True for installing max number of nodes
+            False for installing current running nodes only.
+        Returns:
+            Returns main.TRUE if it successfully installed
+        """
+        result = main.TRUE
+        threads = []
+        i = 0
+        for ctrl in self.controllers if installMax else self.runningNodes:
+            options = "-f"
+            if installMax and i >= self.numCtrls:
+                options = "-nf"
+            result = result and \
+                            main.ONOSbench.onosInstall( node=ctrl.ipAddress, options=options )
+
         return result
 
     def startCLIs( self ):
         """
-        Start the ONOS cli on all controller nodes in the cluster
+        Description:
+            starting Onos using onosCli driver
+        Required:
+        Returns:
+            Returns main.TRUE if it successfully started.
         """
         cliResults =  main.TRUE
         threads = []
-        for ctrl in self.controllers:
+        for ctrl in self.runningNodes:
             t = main.Thread( target=ctrl.CLI.startOnosCli,
                              name="startCli-" + ctrl.name,
                              args=[ ctrl.ipAddress ] )
@@ -110,14 +308,106 @@
             cliResults = cliResults and t.result
         return cliResults
 
-    def command( self, function, args=(), kwargs={} ):
+    def printResult( self, results, activeList, logLevel="debug" ):
+        """
+        Description:
+            Print the value of the list.
+        Required:
+            * results - list of the result
+            * activeList - list of the acitve nodes.
+            * logLevel - Type of log level you want it to be printed.
+        Returns:
+        """
+        f = getattr( main.log, logLevel )
+        for i in range ( len ( results ) ):
+            f( activeList[ i ].name + "'s result : " + str ( results[ i ] ) )
+
+    def allTrueResultCheck( self, results, activeList ):
+        """
+        Description:
+            check if all the result has main.TRUE.
+        Required:
+            * results - list of the result
+            * activeList - list of the acitve nodes.
+        Returns:
+            Returns True if all == main.TRUE else
+            returns False
+        """
+        self.printResult( results, activeList )
+        return all( result == main.TRUE for result in results )
+
+    def notEmptyResultCheck( self, results, activeList ):
+        """
+        Description:
+            check if all the result has any contents
+        Required:
+            * results - list of the result
+            * activeList - list of the acitve nodes.
+        Returns:
+            Returns True if all the results has
+            something else returns False
+        """
+        self.printResult( results, activeList )
+        return all( result for result in results )
+
+    def identicalResultsCheck( self, results, activeList ):
+        """
+        Description:
+            check if all the results has same output.
+        Required:
+            * results - list of the result
+            * activeList - list of the acitve nodes.
+        Returns:
+            Returns True if all the results has
+            same result else returns False
+        """
+        self.printResult( results, activeList )
+        resultOne = results[ 0 ]
+        return all( resultOne == result for result in results )
+
+    def command( self, function, args=(), kwargs={}, returnBool=False, specificDriver=0, contentCheck=False ):
+        """
+        Description:
+            execute some function of the active nodes.
+        Required:
+            * function - name of the function
+            * args - argument of the function
+            * kwargs - kwargs of the funciton
+            * returnBool - True if wish to check all the result has main.TRUE
+            * specificDriver - specific driver to execute the function. Since
+            some of the function can be used in different drivers, it is important
+            to specify which driver it will be executed from.
+                0 - any type of driver
+                1 - from bench
+                2 - from cli
+                3 - from rest
+            * contentCheck - If this is True, it will check if the result has some
+            contents.
+        Returns:
+            Returns results if not returnBool and not contentCheck
+            Returns checkTruthValue of the result if returnBool
+            Returns resultContent of the result if contentCheck
+        """
         """
         Send a command to all ONOS nodes and return the results as a list
+        specificDriver:
+            0 - any type of driver
+            1 - from bench
+            2 - from cli
+            3 - from rest
         """
         threads = []
+        drivers = [ None, "Bench", "CLI", "REST" ]
         results = []
         for ctrl in self.active():
-            f = getattr( ctrl, function )
+            try:
+                f = getattr( ( ctrl if not specificDriver else
+                             getattr( ctrl, drivers[ specificDriver ] ) ), function )
+            except AttributeError:
+                main.log.error( "Function " + function + " not found. Exiting the Test." )
+                main.cleanup()
+                main.exit()
+
             t = main.Thread( target=f,
                              name=function + "-" + ctrl.name,
                              args=args,
@@ -128,4 +418,8 @@
         for t in threads:
             t.join()
             results.append( t.result )
-        return results
+        if returnBool:
+            return self.allTrueResultCheck( results, self.active() )
+        elif contentCheck:
+            return self.notEmptyResultCheck( results, self.active() )
+        return results
\ No newline at end of file