Fix for ONOS-5578

Change-Id: Ibf52263b7a3eaabe4d633aa4bba0781534c82781
diff --git a/TestON/drivers/common/api/controller/onosrestdriver.py b/TestON/drivers/common/api/controller/onosrestdriver.py
index 5cf3274..d5c1114 100755
--- a/TestON/drivers/common/api/controller/onosrestdriver.py
+++ b/TestON/drivers/common/api/controller/onosrestdriver.py
@@ -1337,6 +1337,7 @@
                  udpSrc="",
                  mpls="",
                  priority=100,
+                 groupId="",
                  ip="DEFAULT",
                  port="DEFAULT",
                  debug=False ):
@@ -1375,6 +1376,12 @@
                            "selector": {"criteria":[]}}
             if appId:
                 flowJson[ "appId" ] = appId
+
+            if groupId:
+                flowJson[ 'treatment' ][ 'instructions' ].append( {
+                                                        "type":"GROUP",
+                                                        "groupId":groupId } )
+
             if egressPort:
                 flowJson[ 'treatment' ][ 'instructions' ].append( {
                                                         "type":"OUTPUT",
@@ -1989,3 +1996,180 @@
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanup()
             main.exit()
+
+    def addGroup( self, deviceId, groupType, bucketList, appCookie, groupId, ip="DEFAULT", port="DEFAULT", debug=False ):
+        """
+        Description:
+            Creates a single Group for the specified device.
+        Required:
+            * deviceId: id of the device
+            * type: Type of the Group
+            * bucketList: Buckets to be added to the group
+            * appCookie: Cookie for the Group
+            * groupId: Id of the Group
+        Returns:
+            Returns main.TRUE for successful requests; Returns main.FALSE
+            if error on requests;
+            Returns None for exceptions
+        Note:
+            The ip and port option are for the requests input's ip and port
+            of the ONOS node
+        """
+        try:
+            groupJson = { "type": groupType,
+                          "appCookie": appCookie,
+                          "groupId": groupId,
+                          "buckets": bucketList
+                        }
+            return self.sendGroup( deviceId=deviceId, groupJson=groupJson, ip="DEFAULT", port="DEFAULT", debug=False )
+
+        except ( AttributeError, 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()
+
+    def sendGroup( self, deviceId, groupJson, ip="DEFAULT", port="DEFAULT", debug=False ):
+        """
+        Description:
+            Sends a single group to the specified device.
+        Required:
+            * deviceId: id of the device
+            * groupJson: the group in json
+        Returns:
+            Returns main.TRUE for successful requests; Returns main.FALSE
+            if error on requests;
+            Returns None for exceptions
+        NOTE:
+            The ip and port option are for the requests input's ip and port
+            of the ONOS node
+        """
+        try:
+            if debug: main.log.debug( "Adding group: " + self.pprint( groupJson ) )
+            output = None
+            if ip == "DEFAULT":
+                main.log.warn( "No ip given, reverting to ip from topo file" )
+                ip = self.ip_address
+            if port == "DEFAULT":
+                main.log.warn( "No port given, reverting to port " +
+                               "from topo file" )
+                port = self.port
+            url = "/groups/" + deviceId
+            response = self.send( method="POST",
+                                  url=url, ip = ip, port = port,
+                                  data=json.dumps( groupJson ) )
+            if response:
+                if "201" in str( response[ 0 ] ):
+                    main.log.info( self.name + ": Successfully POST group " +
+                                   "in device: " + str( deviceId ) )
+                    return main.TRUE
+                else:
+                    main.log.error( "Error with REST request, response was: " +
+                                    str( response ) )
+                    return main.FALSE
+        except NotImplementedError as e:
+            raise e  # Inform the caller
+        except ( AttributeError, 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()
+
+    def getGroups( self, deviceId=None, appCookie=None, ip="DEFAULT", port="DEFAULT" ):
+        """
+        Description:
+            Get all the groups or get a specific group by giving the
+            deviceId and appCookie
+        Optional:
+            * deviceId: id of the Device
+            * appCookie: Cookie of the Group
+        Returns:
+            Returns Groups for successful requests; Returns main.FALSE
+            if error on requests;
+            Returns None for exceptions
+        NOTE:
+            The ip and port option are for the requests input's ip and port
+            of the ONOS node
+        """
+        try:
+            output = None
+            if ip == "DEFAULT":
+                main.log.warn( "No ip given, reverting to ip from topo file" )
+                ip = self.ip_address
+            if port == "DEFAULT":
+                main.log.warn( "No port given, reverting to port " +
+                               "from topo file" )
+                port = self.port
+            url = "/groups"
+            if deviceId:
+                url += "/" + deviceId
+                if appCookie:
+                   url += "/" + appCookie
+            response = self.send( url=url, ip = ip, port = port )
+            if response:
+                if 200 <= response[ 0 ] <= 299:
+                    output = response[ 1 ]
+                    groupsJson = json.loads( output ).get( 'groups' )
+                    assert groupsJson is not None, "Error parsing json object"
+                    groups = json.dumps( groupsJson )
+                    return groups
+                else:
+                    main.log.error( "Error with REST request, response was: " +
+                                    str( response ) )
+                    return main.FALSE
+        except ( AttributeError, AssertionError, 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()
+
+    def removeGroup( self, deviceId, appCookie,
+                       ip="DEFAULT", port="DEFAULT" ):
+        """
+        Description:
+            Removes specific device group
+        Required:
+            * deviceId: id of the Device
+            * appCookie: Cookie of the Group
+        Returns:
+            Returns main.TRUE for successful requests; Returns main.FALSE
+            if error on requests;
+            Returns None for exceptions
+        NOTE:
+            The ip and port option are for the requests input's ip and port
+            of the ONOS node
+
+        """
+        try:
+            output = None
+            if ip == "DEFAULT":
+                main.log.warn( "No ip given, reverting to ip from topo file" )
+                ip = self.ip_address
+            if port == "DEFAULT":
+                main.log.warn( "No port given, reverting to port " +
+                               "from topo file" )
+                port = self.port
+            query = "/" + str( deviceId ) + "/" + str( appCookie )
+            response = self.send( method="DELETE",
+                                  url="/groups" + query, ip = ip, port = port )
+            if response:
+                if 200 <= response[ 0 ] <= 299:
+                    return main.TRUE
+                else:
+                    main.log.error( "Error with REST request, response was: " +
+                                    str( response ) )
+                    return main.FALSE
+        except ( AttributeError, 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()
+
diff --git a/TestON/tests/FUNC/FUNCgroup/FUNCgroup.params b/TestON/tests/FUNC/FUNCgroup/FUNCgroup.params
new file mode 100644
index 0000000..585eca3
--- /dev/null
+++ b/TestON/tests/FUNC/FUNCgroup/FUNCgroup.params
@@ -0,0 +1,66 @@
+
+<PARAMS>
+    # CASE - Description
+    # 1    - Variable initialization and optional pull and build ONOS package
+    # 2    - install ONOS
+    # 3    - Start mininet and verify topology
+    # 4    - Testing Scapy
+    # 5    - Testing GROUP with type "ALL"
+    # 6    - Deleting the Group and Flow
+    # 7    - Testing GROUP with type "INDIRECT"
+    # 8    - Deleting the group and flow
+    # 100  - Check logs for Errors and Warnings
+    <testcases>1,2,3,5,6,7,8,100</testcases>
+
+    <SCALE>
+        <max>1</max>
+    </SCALE>
+
+    <DEBUG>on</DEBUG>
+
+    <DEPENDENCY>
+        <path>/tests/FUNC/FUNCgroup/dependencies/</path>
+        <wrapper1>startUp</wrapper1>
+        <wrapper2>topo</wrapper2>
+        <topology>topo-group.py</topology>
+        <bucket>group-bucket</bucket>
+    </DEPENDENCY>
+
+    <ENV>
+        <cellName>productionCell</cellName>
+        <cellApps>drivers,openflow</cellApps>
+    </ENV>
+
+    <GIT>
+        <pull>False</pull>
+        <branch>master</branch>
+    </GIT>
+
+    <CTRL>
+        <port>6653</port>
+    </CTRL>
+
+    <TEST>
+     <swDPID>of:0000000000000001</swDPID>
+     <waitTime>200</waitTime>
+     <appCookie>0x1234abcd</appCookie>
+     <type1>ALL</type1>
+     <type2>INDIRECT</type2>
+     <groupId>1</groupId>
+     <priority>38000</priority>
+     <ingressPort>1</ingressPort>
+     <egressPort1>2</egressPort1>
+     <egressPort2>3</egressPort2>
+     <egressPort3>4</egressPort3>
+    </TEST>
+
+    <SLEEP>
+        <startup>15</startup>
+        <startMN>5</startMN>
+        <addFlow>10</addFlow>
+        <delFlow>10</delFlow>
+        <addGroup>10</addGroup>
+        <delGroup>10</delGroup>
+    </SLEEP>
+
+</PARAMS>
diff --git a/TestON/tests/FUNC/FUNCgroup/FUNCgroup.py b/TestON/tests/FUNC/FUNCgroup/FUNCgroup.py
new file mode 100644
index 0000000..4eb2fb8
--- /dev/null
+++ b/TestON/tests/FUNC/FUNCgroup/FUNCgroup.py
@@ -0,0 +1,748 @@
+class FUNCgroup:
+
+    def __init__( self ):
+        self.default = ''
+
+    def CASE1( self, main ):
+        import os
+        import imp
+
+        """
+        - Construct tests variables
+        - GIT ( optional )
+            - Checkout ONOS master branch
+            - Pull latest ONOS code
+        - Building ONOS ( optional )
+            - Install ONOS package
+            - Build ONOS package
+        """
+        main.case( "Constructing test variables and building ONOS package" )
+        main.step( "Constructing test variables" )
+
+        # Test variables
+        main.testOnDirectory = os.path.dirname( os.getcwd ( ) )
+        main.cellName = main.params[ 'ENV' ][ 'cellName' ]
+        main.apps = main.params[ 'ENV' ][ 'cellApps' ]
+        gitBranch = main.params[ 'GIT' ][ 'branch' ]
+        gitPull = main.params[ 'GIT' ][ 'pull' ]
+        main.ONOSport = main.params[ 'CTRL' ][ 'port' ]
+        main.dependencyPath = main.testOnDirectory + \
+                              main.params[ 'DEPENDENCY' ][ 'path' ]
+        wrapperFile1 = main.params[ 'DEPENDENCY' ][ 'wrapper1' ]
+        wrapperFile2 = main.params[ 'DEPENDENCY' ][ 'wrapper2' ]
+        main.topology = main.params[ 'DEPENDENCY' ][ 'topology' ]
+        bucket = main.params[ 'DEPENDENCY' ][ 'bucket' ]
+        main.maxNodes = int( main.params[ 'SCALE' ][ 'max' ] )
+        main.startUpSleep = int( main.params[ 'SLEEP' ][ 'startup' ] )
+        main.startMNSleep = int( main.params[ 'SLEEP' ][ 'startMN' ] )
+        main.addFlowSleep = int( main.params[ 'SLEEP' ][ 'addFlow' ] )
+        main.delFlowSleep = int( main.params[ 'SLEEP' ][ 'delFlow' ] )
+        main.addGroupSleep = int( main.params[ 'SLEEP' ][ 'addGroup' ] )
+        main.delGroupSleep = int( main.params[ 'SLEEP' ][ 'delGroup' ] )
+        main.debug = main.params[ 'DEBUG' ]
+        main.swDPID = main.params[ 'TEST' ][ 'swDPID' ]
+        egressPort1 = main.params[ 'TEST' ][ 'egressPort1' ]
+        egressPort2 = main.params[ 'TEST' ][ 'egressPort2' ]
+        egressPort3 = main.params[ 'TEST' ][ 'egressPort3' ]
+        ingressPort = main.params[ 'TEST' ][ 'ingressPort' ]
+        appCookie = main.params[ 'TEST' ][ 'appCookie' ]
+        type1 = main.params[ 'TEST' ][ 'type1' ]
+        type2 = main.params[ 'TEST' ][ 'type2' ]
+        groupId = main.params[ 'TEST' ][ 'groupId' ]
+        priority = main.params[ 'TEST' ][ 'priority' ]
+        deviceId = main.params[ 'TEST' ][ 'swDPID' ]
+
+        main.cellData = { } # for creating cell file
+        main.CLIs = [ ]
+        main.ONOSip = [ ]
+
+        main.debug = True if "on" in main.debug else False
+
+        main.ONOSip = main.ONOSbench.getOnosIps( )
+
+        # Assigning ONOS cli handles to a list
+        for i in range( 1,  main.maxNodes + 1 ):
+            main.CLIs.append( getattr( main, 'ONOScli' + str( i ) ) )
+
+        # -- INIT SECTION, ONLY RUNS ONCE -- #
+        main.startUp = imp.load_source( wrapperFile1,
+                                        main.dependencyPath +
+                                        wrapperFile1 +
+                                        ".py" )
+
+        main.topo = imp.load_source( wrapperFile2,
+                                     main.dependencyPath +
+                                     wrapperFile2 +
+                                     ".py" )
+
+        main.buckets = imp.load_source( bucket,
+                                        main.dependencyPath +
+                                        bucket +
+                                        ".py" )
+
+        copyResult = main.ONOSbench.scp( main.Mininet1,
+                                         main.dependencyPath + main.topology,
+                                         main.Mininet1.home + '/custom/',
+                                         direction="to" )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=copyResult,
+                                 onpass="Successfully copy " + "test variables ",
+                                 onfail="Failed to copy test variables" )
+
+        if main.CLIs:
+            stepResult = main.TRUE
+        else:
+            main.log.error( "Did not properly created list of ONOS CLI handle" )
+            stepResult = main.FALSE
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="Successfully construct " + "test variables ",
+                                 onfail="Failed to construct test variables" )
+
+        if gitPull == 'True':
+            main.step( "Building ONOS in " + gitBranch + " branch" )
+            onosBuildResult = main.startUp.onosBuild( main, gitBranch )
+            stepResult = onosBuildResult
+            utilities.assert_equals( expect=main.TRUE,
+                                     actual=stepResult,
+                                     onpass="Successfully compiled " + "latest ONOS",
+                                     onfail="Failed to compile " + "latest ONOS" )
+        else:
+            main.log.warn( "Did not pull new code so skipping mvn " +
+                           "clean install" )
+
+    def CASE2( self, main ):
+        """
+        - Set up cell
+            - Create cell file
+            - Set cell file
+            - Verify cell file
+        - Kill ONOS process
+        - Uninstall ONOS cluster
+        - Verify ONOS start up
+        - Install ONOS cluster
+        - Connect to cli
+        """
+        import time
+
+        main.numCtrls = int( main.maxNodes )
+
+        main.case( "Starting up " + str( main.numCtrls ) +
+                   " node(s) ONOS cluster" )
+
+        #kill off all onos processes
+        main.log.info( "Safety check, killing all ONOS processes" +
+                       " before initiating environment setup" )
+
+        for i in range( main.maxNodes ):
+            main.ONOSbench.onosDie( main.ONOSip[ i ] )
+
+        main.log.info( "NODE COUNT = " + str( main.numCtrls ) )
+
+        tempOnosIp = [ ]
+        for i in range( main.numCtrls ):
+            tempOnosIp.append( main.ONOSip[ i ] )
+
+        main.ONOSbench.createCellFile( main.ONOSbench.ip_address,
+                                       "temp",
+                                       main.Mininet1.ip_address,
+                                       main.apps,
+                                       tempOnosIp )
+
+        main.step( "Apply cell to environment" )
+        cellResult = main.ONOSbench.setCell( "temp" )
+        verifyResult = main.ONOSbench.verifyCell( )
+        stepResult = cellResult and verifyResult
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="Successfully applied cell to " + "environment",
+                                 onfail="Failed to apply cell to environment " )
+
+        main.step( "Creating ONOS package" )
+        packageResult = main.ONOSbench.buckBuild()
+        stepResult = packageResult
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="Successfully created ONOS package",
+                                 onfail="Failed to create ONOS package" )
+
+        time.sleep( main.startUpSleep )
+        main.step( "Uninstalling ONOS package" )
+        onosUninstallResult = main.TRUE
+        for ip in main.ONOSip:
+            onosUninstallResult = onosUninstallResult and \
+                    main.ONOSbench.onosUninstall( nodeIp=ip )
+        stepResult = onosUninstallResult
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="Successfully uninstalled ONOS package",
+                                 onfail="Failed to uninstall ONOS package" )
+        time.sleep( main.startUpSleep )
+        main.step( "Installing ONOS package" )
+        onosInstallResult = main.TRUE
+        for i in range( main.numCtrls ):
+            onosInstallResult = onosInstallResult and \
+                    main.ONOSbench.onosInstall( node=main.ONOSip[ i ] )
+        stepResult = onosInstallResult
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="Successfully installed ONOS package",
+                                 onfail="Failed to install ONOS package" )
+
+        time.sleep( main.startUpSleep )
+        main.step( "Starting ONOS service" )
+        stopResult = main.TRUE
+        startResult = main.TRUE
+        onosIsUp = main.TRUE
+
+        for i in range( main.numCtrls ):
+            onosIsUp = onosIsUp and main.ONOSbench.isup( main.ONOSip[ i ] )
+        if onosIsUp == main.TRUE:
+            main.log.report( "ONOS instance is up and ready" )
+        else:
+            main.log.report( "ONOS instance may not be up, stop and " +
+                             "start ONOS again " )
+            for i in range( main.numCtrls ):
+                stopResult = stopResult and \
+                        main.ONOSbench.onosStop( main.ONOSip[ i ] )
+            for i in range( main.numCtrls ):
+                startResult = startResult and \
+                        main.ONOSbench.onosStart( main.ONOSip[ i ] )
+        stepResult = onosIsUp and stopResult and startResult
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="ONOS service is ready",
+                                 onfail="ONOS service did not start properly" )
+
+        main.step( "Set up ONOS secure SSH" )
+        secureSshResult = main.TRUE
+        for i in range( int( main.numCtrls ) ):
+            secureSshResult = secureSshResult and main.ONOSbench.onosSecureSSH( node=main.ONOSip[i] )
+        utilities.assert_equals( expect=main.TRUE, actual=secureSshResult,
+                                 onpass="Test step PASS",
+                                 onfail="Test step FAIL" )
+
+        main.step( "Start ONOS cli" )
+        cliResult = main.TRUE
+        for i in range( main.numCtrls ):
+            cliResult = cliResult and \
+                        main.CLIs[ i ].startOnosCli( main.ONOSip[ i ] )
+        stepResult = cliResult
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="Successfully start ONOS cli",
+                                 onfail="Failed to start ONOS cli" )
+
+    def CASE3( self, main ):
+        '''
+            Start Mininet
+        '''
+        import json
+
+        main.case( "Setup mininet and compare ONOS topology view to Mininet topology" )
+        main.caseExplanation = "Start mininet with custom topology and compare topology " +\
+                "elements between Mininet and ONOS"
+
+        main.step( "Setup Mininet Topology" )
+        topology = main.Mininet1.home + '/custom/' + main.topology
+        stepResult = main.Mininet1.startNet( topoFile = topology )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="Successfully loaded topology",
+                                 onfail="Failed to load topology" )
+
+        main.step( "Assign switch to controller" )
+        stepResult = main.Mininet1.assignSwController( "s1", main.ONOSip[0] )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="Successfully assigned switch to controller",
+                                 onfail="Failed to assign switch to controller" )
+
+        time.sleep( main.startMNSleep )
+
+        main.step( "Comparing MN topology to ONOS topology" )
+        main.log.info( "Gathering topology information" )
+        devices = main.topo.getAllDevices( main )
+        hosts = main.topo.getAllHosts( main )
+        ports = main.topo.getAllPorts( main )
+        links = main.topo.getAllLinks( main )
+
+        mnSwitches = main.Mininet1.getSwitches( )
+        mnLinks = main.Mininet1.getLinks( )
+        mnHosts = main.Mininet1.getHosts( )
+
+        for controller in range( main.numCtrls ):
+            controllerStr = str( controller + 1 )
+            if devices[ controller ] and ports[ controller ] and\
+                "Error" not in devices[ controller ] and\
+                "Error" not in ports[ controller ]:
+
+                currentDevicesResult = main.Mininet1.compareSwitches(
+                        mnSwitches,
+                        json.loads( devices[ controller ] ),
+                        json.loads( ports[ controller ] ) )
+            else:
+                currentDevicesResult = main.FALSE
+            utilities.assert_equals( expect=main.TRUE,
+                                     actual=currentDevicesResult,
+                                     onpass="ONOS" + controllerStr +
+                                            " Switches view is correct",
+                                     onfail="ONOS" + controllerStr +
+                                            " Switches view is incorrect" )
+            if links[ controller ] and "Error" not in links[ controller ]:
+                currentLinksResult = main.Mininet1.compareLinks(
+                        mnSwitches, mnLinks,
+                        json.loads( links[ controller ] ) )
+            else:
+                currentLinksResult = main.FALSE
+            utilities.assert_equals( expect=main.TRUE,
+                                     actual=currentLinksResult,
+                                     onpass="ONOS" + controllerStr +
+                                            " links view is correct",
+                                     onfail="ONOS" + controllerStr +
+                                            " links view is incorrect" )
+
+            if hosts[ controller ] or "Error" not in hosts[ controller ]:
+                currentHostsResult = main.Mininet1.compareHosts(
+                        mnHosts,
+                        json.loads( hosts[ controller ] ) )
+            else:
+                currentHostsResult = main.FALSE
+            utilities.assert_equals( expect=main.TRUE,
+                                     actual=currentHostsResult,
+                                     onpass="ONOS" + controllerStr +
+                                            " hosts exist in Mininet",
+                                     onfail="ONOS" + controllerStr +
+                                            " hosts don't match Mininet")
+
+
+    def CASE4( self, main ):
+        '''
+        Testing scapy
+        '''
+        main.case( "Testing scapy" )
+        main.step( "Creating Host1 component" )
+        main.Scapy.createHostComponent( "h1" )
+        main.Scapy.createHostComponent( "h2" )
+        hosts = [ main.h1, main.h2 ]
+        for host in hosts:
+            host.startHostCli( )
+            host.startScapy( )
+            host.updateSelf( )
+            main.log.debug( host.name )
+            main.log.debug( host.hostIp )
+            main.log.debug( host.hostMac )
+
+        main.step( "Sending/Receiving Test packet - Filter doesn't match" )
+        main.log.info( "Starting Filter..." )
+        main.h2.startFilter( )
+        main.log.info( "Building Ether frame..." )
+        main.h1.buildEther( dst=main.h2.hostMac )
+        main.log.info( "Sending Packet..." )
+        main.h1.sendPacket( )
+        main.log.info( "Checking Filter..." )
+        finished = main.h2.checkFilter( )
+        main.log.debug( finished )
+        i = ""
+        if finished:
+            a = main.h2.readPackets( )
+            for i in a.splitlines( ):
+                main.log.info( i )
+        else:
+            kill = main.h2.killFilter( )
+            main.log.debug( kill )
+            main.h2.handle.sendline( "" )
+            main.h2.handle.expect( main.h2.scapyPrompt )
+            main.log.debug( main.h2.handle.before )
+        utilities.assert_equals( expect=True,
+                                 actual="dst=00:00:00:00:00:02 src=00:00:00:00:00:01" in i,
+                                 onpass="Pass",
+                                 onfail="Fail" )
+
+        main.step( "Sending/Receiving Test packet - Filter matches" )
+        main.h2.startFilter( )
+        main.h1.buildEther( dst=main.h2.hostMac )
+        main.h1.buildIP( dst=main.h2.hostIp )
+        main.h1.sendPacket( )
+        finished = main.h2.checkFilter( )
+        i = ""
+        if finished:
+            a = main.h2.readPackets( )
+            for i in a.splitlines( ):
+                main.log.info( i )
+        else:
+            kill = main.h2.killFilter( )
+            main.log.debug( kill )
+            main.h2.handle.sendline( "" )
+            main.h2.handle.expect( main.h2.scapyPrompt )
+            main.log.debug( main.h2.handle.before )
+        utilities.assert_equals( expect=True,
+                                 actual="dst=00:00:00:00:00:02 src=00:00:00:00:00:01" in i,
+                                 onpass="Pass",
+                                 onfail="Fail" )
+
+
+
+        main.step( "Clean up host components" )
+        for host in hosts:
+            host.stopScapy( )
+        main.Mininet1.removeHostComponent( "h1" )
+        main.Mininet1.removeHostComponent( "h2" )
+
+    def CASE5( self, main ):
+        '''
+           Adding Group of type "ALL" using Rest api
+        '''
+        import json
+        import time
+        isAdded = main.FALSE
+        main.case( "Verify Group of type All are successfully Added" )
+        main.caseExplanation = " Install a Group of type ALL " +\
+                               " Verify the Group is Added " +\
+                               " Add a flow using the group " +\
+                               " Send a packet that verifies the action bucket of the group"
+
+        main.step( "Add Group using Rest api" )
+        bucketList = []
+        bucket = main.buckets.addBucket( main, egressPort = egressPort1 )
+        bucketList.append( bucket )
+        bucket = main.buckets.addBucket( main, egressPort = egressPort2 )
+        bucketList.append( bucket )
+        bucket = main.buckets.addBucket( main, egressPort = egressPort3 )
+        bucketList.append( bucket )
+        response = main.ONOSrest.addGroup( deviceId = deviceId,
+                                           groupType = type1,
+                                           bucketList = bucketList,
+                                           appCookie = appCookie,
+                                           groupId = groupId )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=response,
+                                 onpass="Successfully added Groups of type ALL",
+                                 onfail="Failed to add Groups of type ALL" )
+
+        # Giving ONOS time to add the group
+        time.sleep( main.addGroupSleep )
+
+        main.step( "Check groups are in ADDED state" )
+
+        response = main.ONOSrest.getGroups( deviceId = deviceId,
+                                            appCookie = appCookie )
+        responsejson = json.loads( response )
+        for item in responsejson :
+            if item["state"] == "ADDED" :
+                isAdded = main.TRUE
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=isAdded,
+                                 onpass="All Group is in Added State",
+                                 onfail="All Group is not in Added State" )
+
+        '''
+           Adding flow using rest api
+        '''
+        isAdded = main.FALSE
+
+        main.step( "Adding flow with Group using rest api" )
+        response = main.ONOSrest.addFlow( deviceId = deviceId,
+                                          priority = priority,
+                                          ingressPort = ingressPort,
+                                          groupId = groupId )
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=response,
+                                 onpass="Successfully Added Flows",
+                                 onfail="Failed to Add flows" )
+
+        # Giving ONOS time to add the flow
+        time.sleep( main.addFlowSleep )
+
+        response = main.ONOSrest.getFlows( deviceId = deviceId )
+        responsejson = json.loads( response )
+        for item in responsejson :
+            if item["priority"] == int( priority ) and item["state"] == "ADDED" :
+                isAdded = main.TRUE
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=isAdded,
+                                 onpass="Flow is in Added State",
+                                 onfail="Flow is not in Added State" )
+
+        '''
+        Sends a packet using  scapy
+        '''
+        main.step( "Testing Group by sending packet using  Scapy" )
+        main.log.info( "Creating host components" )
+        main.Scapy.createHostComponent( "h1" )
+        main.Scapy.createHostComponent( "h2" )
+        main.Scapy.createHostComponent( "h3" )
+        main.Scapy.createHostComponent( "h4" )
+
+        hosts = [main.h1, main.h2, main.h3, main.h4]
+        for host in hosts:
+            host.startHostCli( )
+            host.startScapy( )
+            host.updateSelf( )
+        main.log.info( "Constructing Packet" )
+        main.h1.buildEther( dst=main.h1.hostMac )
+        main.h1.buildIP( dst=main.h1.hostIp )
+        main.log.info( "Start Filter on host2,host3,host4" )
+        main.h2.startFilter( pktFilter="ether host %s and ip host %s" % ( main.h1.hostMac, main.h1.hostIp ) )
+        main.h3.startFilter( pktFilter="ether host %s and ip host %s" % ( main.h1.hostMac, main.h1.hostIp ) )
+        main.h4.startFilter( pktFilter="ether host %s and ip host %s" % ( main.h1.hostMac, main.h1.hostIp ) )
+        main.log.info( "sending packet to Host" )
+        main.h1.sendPacket( )
+        main.log.info( "Checking filter for our packet" )
+        stepResultH2 = main.h2.checkFilter( )
+        stepResultH3 = main.h3.checkFilter( )
+        stepResultH4 = main.h4.checkFilter( )
+
+        if stepResultH2:
+            main.log.info( "Packet : %s" % main.h2.readPackets( ) )
+        else:
+            main.h2.killFilter( )
+
+        if stepResultH3:
+            main.log.info( "Packet : %s" % main.h3.readPackets( ) )
+        else:
+            main.h2.killFilter( )
+
+        if stepResultH4:
+            main.log.info( "Packet : %s" % main.h4.readPackets( ) )
+        else:
+            main.h4.killFilter( )
+
+        if stepResultH2 and stepResultH3 and stepResultH4 :
+            main.log.info( "Success!!!Packet sent to port 1 is received at port 2,3 and 4" )
+            stepResult = main.TRUE
+        else:
+            main.log.info( "Failure!!!Packet sent to port 1 is not received at port 2,3 and 4" )
+            stepResult = main.FALSE
+
+        main.log.info( "Clean up host components" )
+        for host in hosts:
+            host.stopScapy( )
+        main.Mininet1.removeHostComponent( "h1" )
+        main.Mininet1.removeHostComponent( "h2" )
+        main.Mininet1.removeHostComponent( "h3" )
+        main.Mininet1.removeHostComponent( "h4" )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="Packet sent to port 1 is received at port 2,3,4 ",
+                                 onfail="Packet sent to port 1 is not received at port 2,3,4 " )
+
+    def CASE6( self, main ):
+        '''
+         Deleting the Group and Flow
+        '''
+        import json
+        import time
+        respFlowId = 1
+
+        main.case( "Delete the Group and Flow added through Rest api " )
+        main.step( "Deleting Group and Flows" )
+
+        #Get Flow ID
+        response = main.ONOSrest.getFlows( deviceId = deviceId )
+        responsejson = json.loads( response )
+        for item in responsejson :
+            if item["priority"] == int( priority ) :
+                respFlowId = item["id"]
+
+        main.step( "Deleting the created flow by deviceId and flowId" )
+        flowResponse = main.ONOSrest.removeFlow( deviceId = deviceId,
+                                          flowId = respFlowId )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=flowResponse,
+                                 onpass="Deleting flow is successful!!!",
+                                 onfail="Deleting flow is failure!!!" )
+
+        # Giving ONOS time to delete the flow
+        time.sleep( main.delFlowSleep )
+
+        main.step( "Deleting the created group by deviceId and appCookie" )
+        groupResponse = main.ONOSrest.removeGroup( deviceId = deviceId,
+                                                   appCookie = appCookie )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=groupResponse,
+                                 onpass="Deleting Group is successful!!!",
+                                 onfail="Deleting Group is failure!!!" )
+
+        # Giving ONOS time to delete the group
+        time.sleep( main.delGroupSleep )
+
+    def CASE7( self, main ):
+        '''
+           Adding Group of type "INDIRECT" using Rest api.
+        '''
+        import json
+        import time
+        isAdded = main.FALSE
+
+        main.case( "Verify Group of type INDIRECT are successfully Added" )
+        main.caseExplanation = " Install a Group of type INDIRECT " +\
+                               " Verify the Group is Added " +\
+                               " Add a flow using the group " +\
+                               " Send a packet that verifies the action bucket of the group"
+
+        main.step( "Add Group using Rest api" )
+        bucketList = []
+        bucket = main.buckets.addBucket( main, egressPort = egressPort1 )
+        bucketList.append( bucket )
+        response = main.ONOSrest.addGroup( deviceId = deviceId,
+                                           groupType = type2,
+                                           bucketList = bucketList,
+                                           appCookie = appCookie,
+                                           groupId = groupId )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=response,
+                                 onpass="Successfully added Groups of type INDIRECT",
+                                 onfail="Failed to add Groups of type INDIRECT" )
+
+        # Giving ONOS time to add the group
+        time.sleep( main.addGroupSleep )
+
+        main.step( "Check groups are in ADDED state" )
+
+        response = main.ONOSrest.getGroups( deviceId = deviceId,
+                                            appCookie = appCookie )
+        responsejson = json.loads( response )
+        for item in responsejson :
+            if item["state"] == "ADDED" :
+                isAdded = main.TRUE
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=isAdded,
+                                 onpass="INDIRECT Group is in Added State",
+                                 onfail="INDIRECT Group is not in Added State" )
+
+        '''
+           Adding flows using rest api
+        '''
+        isAdded = main.FALSE
+
+        main.step( "Adding flow with Group using rest api" )
+        response = main.ONOSrest.addFlow( deviceId = deviceId,
+                                          priority = priority,
+                                          ingressPort = ingressPort,
+                                          groupId = groupId )
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=response,
+                                 onpass="Successfully Added Flows",
+                                 onfail="Failed to Add flows" )
+
+        # Giving ONOS time to add the flow
+        time.sleep( main.addFlowSleep )
+
+        response = main.ONOSrest.getFlows( deviceId = deviceId )
+        responsejson = json.loads( response )
+        for item in responsejson :
+            if item["priority"] == int( priority ) and item["state"] == "ADDED" :
+                isAdded = main.TRUE
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=isAdded,
+                                 onpass="Flow is in Added State",
+                                 onfail="Flow is not in Added State" )
+
+        '''
+        Sends a packet using scapy
+        '''
+        main.step( "Testing Group by sending packet using  Scapy" )
+        main.log.info( "Creating host components" )
+        main.Scapy.createHostComponent( "h1" )
+        main.Scapy.createHostComponent( "h2" )
+
+        hosts = [main.h1, main.h2]
+        for host in hosts:
+            host.startHostCli( )
+            host.startScapy( )
+            host.updateSelf( )
+        main.log.info( "Constructing Packet" )
+        main.h1.buildEther( dst=main.h1.hostMac )
+        main.h1.buildIP( dst=main.h1.hostIp )
+        main.log.info( "Start Filter on host2" )
+        main.h2.startFilter( pktFilter="ether host %s and ip host %s" % ( main.h1.hostMac, main.h1.hostIp ) )
+        main.log.info( "sending packet to Host" )
+        main.h1.sendPacket( )
+        main.log.info( "Checking filter for our packet" )
+        stepResultH2 = main.h2.checkFilter( )
+
+        if stepResultH2:
+            main.log.info( "Packet : %s" % main.h2.readPackets( ) )
+        else:
+            main.h2.killFilter( )
+
+        main.log.info( "Clean up host components" )
+        for host in hosts:
+            host.stopScapy( )
+        main.Mininet1.removeHostComponent( "h1" )
+        main.Mininet1.removeHostComponent( "h2" )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResultH2,
+                                 onpass="Packet sent to port 1 is received at port 2 successfully!!!",
+                                 onfail="Failure!!!Packet sent to port 1 is not received at port 2" )
+
+    def CASE8( self, main ):
+        '''
+         Deleting the Group and Flow
+        '''
+        import json
+        import time
+        respFlowId = 1
+
+        main.case( "Delete the Group and Flow added through Rest api " )
+        main.step( "Deleting Group and Flows" )
+
+        #Getting Flow ID
+        response = main.ONOSrest.getFlows( deviceId = deviceId )
+        responsejson = json.loads( response )
+        for item in responsejson :
+            if item["priority"] == int( priority ) :
+                respFlowId = item["id"]
+
+        main.step( "Deleting the created flow by deviceId and flowId" )
+        flowResponse = main.ONOSrest.removeFlow( deviceId = deviceId,
+                                          flowId = respFlowId )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=flowResponse,
+                                 onpass="Deleting flow is successful!!!",
+                                 onfail="Deleting flow is failure!!!" )
+
+        # Giving ONOS time to delete the flow
+        time.sleep( main.delFlowSleep )
+
+        groupResponse = main.ONOSrest.removeGroup( deviceId = deviceId,
+                                          appCookie = appCookie )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=groupResponse,
+                                 onpass="Deleting Group is successful!!!",
+                                 onfail="Deleting Group is failure!!!" )
+
+        # Giving ONOS time to delete the group
+        time.sleep( main.delGroupSleep )
+
+    def CASE100( self, main ):
+        '''
+            Report errors/warnings/exceptions
+        '''
+        main.log.info( "Error report: \n" )
+        main.ONOSbench.logReport( main.ONOSip[ 0 ],
+                                  [ "INFO",
+                                    "FOLLOWER",
+                                    "WARN",
+                                    "flow",
+                                    "group",
+                                    "ERROR",
+                                    "Except" ],
+                                  "s" )
diff --git a/TestON/tests/FUNC/FUNCgroup/FUNCgroup.topo b/TestON/tests/FUNC/FUNCgroup/FUNCgroup.topo
new file mode 100644
index 0000000..50e5d63
--- /dev/null
+++ b/TestON/tests/FUNC/FUNCgroup/FUNCgroup.topo
@@ -0,0 +1,54 @@
+<TOPOLOGY>
+    <COMPONENT>
+
+        <ONOSbench>
+            <host>localhost</host>
+            <user>sdn</user>
+            <password>rocks</password>
+            <type>OnosDriver</type>
+            <connect_order>1</connect_order>
+            <COMPONENTS>
+                <nodes>3</nodes>
+            </COMPONENTS>
+        </ONOSbench>
+
+        <ONOScli1>
+            <host>localhost</host>
+            <user>sdn</user>
+            <password>rocks</password>
+            <type>OnosCliDriver</type>
+            <connect_order>2</connect_order>
+            <COMPONENTS>
+            </COMPONENTS>
+        </ONOScli1>
+
+        <Mininet1>
+            <host>OCN</host>
+            <user>sdn</user>
+            <password>rocks</password>
+            <type>MininetCliDriver</type>
+            <connect_order>5</connect_order>
+            <COMPONENTS> </COMPONENTS>
+        </Mininet1>
+
+        <ONOSrest>
+            <host>OC1</host>
+            <port>8181</port>
+            <user>onos</user>
+            <password>rocks</password>
+            <type>OnosRestDriver</type>
+            <connect_order>6</connect_order>
+            <COMPONENTS>
+            </COMPONENTS>
+        </ONOSrest>
+
+        <Scapy>
+            <host>OCN</host>
+            <user>sdn</user>
+            <password>rocks</password>
+            <type>ScapyCliDriver</type>
+            <connect_order>7</connect_order>
+        </Scapy>
+
+    </COMPONENT>
+</TOPOLOGY>
diff --git a/TestON/tests/FUNC/FUNCgroup/README b/TestON/tests/FUNC/FUNCgroup/README
new file mode 100644
index 0000000..ac903d7
--- /dev/null
+++ b/TestON/tests/FUNC/FUNCgroup/README
@@ -0,0 +1,43 @@
+FUNCgroup test suite
+
+Summary:
+
+        The purpose of this test suite is to test the Group Subsystem.
+        As part of this test, we are testing the functionality of the Group Subsystem.
+        Install a group of type ‘ALL’ whose bucket will have treatments of type ‘OUTPUT’ to port 2,3, and 4 respectively.
+        Install a flow which will have selector criteria IN_PORT as port 1 and Instructions as type ‘Group’ with the Group Id already created.
+        Verify when port 1 receives any packet, it should follow the actions which are mentioned in the Group and send the packet to port 2, 3 and 4.
+
+Topology:
+        The topology consists of one switch with four hosts connected to it.
+
+Required:
+        Ths test requires Mininet topology file topo-group.py located in the dependencies folder.
+        You will also need to install the Python module, Scapy.
+
+Test Description:
+    # CASE - Description
+    # 1    - Variable initialization and optional pull and build ONOS package
+    # 2    - install ONOS
+    # 3    - Start mininet and verify topology
+    # 4    - Testing Scapy
+    # 5    - Testing GROUP with type "ALL"
+             # 5.1 - Adds a Group with type ‘ALL’ and whose bucket will have treatments as type ‘OUTPUT’
+                     to port 2, 3,  4 respectively and verify if the Group was added correctly.
+             # 5.2 - Adds a flow with selector criteria as IN_PORT 1 and Instructions as type ‘Group’
+                     with GroupId already created and tests if the flow was added correctly.
+             # 5.3 - Sends a packet using SCAPY to port 1 of the device and check whether the
+                     same packet was received at port 2, 3, and 4 of the device.
+    # 6    - Deleting the Group and Flow
+    # 7    - Testing GROUP with type "INDIRECT"
+             # 7.1 - Adds a Group with type ‘INDIRECT’ and whose bucket will have treatments
+                     as type ‘OUTPUT’ to port 2 respectively and verify  if the Group was added correctly
+             # 7.2 - Adds a flow with selector criteria as IN_PORT 1 and Instructions as  type ‘Group’
+                     with GroupId already created and tests if the flow was added correctly.
+             # 7.3 - Sends a packet using SCAPY to port 1 of the device and check whether
+                     the same packet was received at port 2 of the device.
+    # 8    - Deleting the group and flow
+
+
+Scapy install:
+    sudo apt-get install Scapy
diff --git a/TestON/tests/FUNC/FUNCgroup/__init__.py b/TestON/tests/FUNC/FUNCgroup/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/TestON/tests/FUNC/FUNCgroup/__init__.py
diff --git a/TestON/tests/FUNC/FUNCgroup/dependencies/group-bucket.py b/TestON/tests/FUNC/FUNCgroup/dependencies/group-bucket.py
new file mode 100644
index 0000000..290a26a
--- /dev/null
+++ b/TestON/tests/FUNC/FUNCgroup/dependencies/group-bucket.py
@@ -0,0 +1,31 @@
+def addBucket( main , egressPort = "" ):
+       """
+       Description:
+            Create a single bucket which can be added to a Group.
+       Optional:
+            * egressPort: port of egress device
+       Returns:
+            * Returns a Bucket
+            * Returns None in case of error
+       Note:
+            The ip and port option are for the requests input's ip and port
+            of the ONOS node.
+       """
+       try:
+
+           bucket = {
+                        "treatment":{ "instructions":[] }
+                    }
+           if egressPort:
+               bucket[ 'treatment' ][ 'instructions' ].append( {
+                                                        "type":"OUTPUT",
+                                                        "port":egressPort } )
+           return bucket
+
+       except ( AttributeError, 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()
diff --git a/TestON/tests/FUNC/FUNCgroup/dependencies/startUp.py b/TestON/tests/FUNC/FUNCgroup/dependencies/startUp.py
new file mode 100644
index 0000000..bf2a2b6
--- /dev/null
+++ b/TestON/tests/FUNC/FUNCgroup/dependencies/startUp.py
@@ -0,0 +1,38 @@
+"""
+    This wrapper function is use for starting up onos instance
+"""
+
+import time
+import os
+import json
+
+def onosBuild( main, gitBranch ):
+    """
+        This includes pulling ONOS and building it using maven install
+    """
+
+    buildResult = main.FALSE
+
+    # Git checkout a branch of ONOS
+    checkOutResult = main.ONOSbench.gitCheckout( gitBranch )
+    # Does the git pull on the branch that was checked out
+    if not checkOutResult:
+        main.log.warn( "Failed to checked out " + gitBranch +
+                                           " branch")
+    else:
+        main.log.info( "Successfully checked out " + gitBranch +
+                                           " branch")
+    gitPullResult = main.ONOSbench.gitPull()
+    if gitPullResult == main.ERROR:
+        main.log.error( "Error pulling git branch" )
+    else:
+        main.log.info( "Successfully pulled " + gitBranch + " branch" )
+
+    # Maven clean install
+    buildResult = main.ONOSbench.cleanInstall()
+
+    return buildResult
+
+
+
+
diff --git a/TestON/tests/FUNC/FUNCgroup/dependencies/topo-group.py b/TestON/tests/FUNC/FUNCgroup/dependencies/topo-group.py
new file mode 100644
index 0000000..14e28e5
--- /dev/null
+++ b/TestON/tests/FUNC/FUNCgroup/dependencies/topo-group.py
@@ -0,0 +1,49 @@
+#!/usr/bin/python
+
+"""
+Custom topology for Mininet
+"""
+from mininet.topo import Topo
+from mininet.net import Mininet
+from mininet.node import Host, RemoteController
+from mininet.node import Node
+from mininet.node import CPULimitedHost
+from mininet.link import TCLink
+from mininet.cli import CLI
+from mininet.log import setLogLevel
+from mininet.util import dumpNodeConnections
+from mininet.node import ( UserSwitch, OVSSwitch, IVSSwitch )
+
+class MyTopo( Topo ):
+
+    def __init__( self, **opts ):
+        # Initialize topology
+        Topo.__init__( self, **opts)
+
+        # IPv4 hosts
+        host1=self.addHost( 'h1', ip='10.0.0.1/24' )
+        host2=self.addHost( 'h2', ip='10.0.0.2/24' )
+        host3=self.addHost( 'h3', ip='10.0.0.3/24' )
+        host4=self.addHost( 'h4', ip='10.0.0.4/24' )
+
+        s1 = self.addSwitch( 's1' )
+
+        self.addLink(s1, host1)
+        self.addLink(s1, host2)
+        self.addLink(s1, host3)
+        self.addLink(s1, host4)
+
+        topos = { 'mytopo': ( lambda: MyTopo() ) }
+
+def setupNetwork():
+    "Create network"
+    topo = MyTopo()
+    network = Mininet(topo=topo, autoSetMacs=True, autoStaticArp=True, controller=None)
+    network.start()
+    CLI( network )
+    network.stop()
+
+if __name__ == '__main__':
+    setLogLevel('info')
+    #setLogLevel('debug')
+    setupNetwork()
diff --git a/TestON/tests/FUNC/FUNCgroup/dependencies/topo.py b/TestON/tests/FUNC/FUNCgroup/dependencies/topo.py
new file mode 100644
index 0000000..b44e3fc
--- /dev/null
+++ b/TestON/tests/FUNC/FUNCgroup/dependencies/topo.py
@@ -0,0 +1,100 @@
+"""
+    These functions can be used for topology comparisons
+"""
+
+import time
+import os
+import json
+
+def getAllDevices( main ):
+    """
+        Return a list containing the devices output from each ONOS node
+    """
+    devices = []
+    threads = []
+    for i in range( main.numCtrls ):
+        t = main.Thread( target=main.CLIs[i].devices,
+                         name="devices-" + str( i ),
+                         args=[ ] )
+        threads.append( t )
+        t.start()
+
+    for t in threads:
+        t.join()
+        devices.append( t.result )
+    return devices
+
+def getAllHosts( main ):
+    """
+        Return a list containing the hosts output from each ONOS node
+    """
+    hosts = []
+    ipResult = main.TRUE
+    threads = []
+    for i in range( main.numCtrls ):
+        t = main.Thread( target=main.CLIs[i].hosts,
+                         name="hosts-" + str( i ),
+                         args=[ ] )
+        threads.append( t )
+        t.start()
+
+    for t in threads:
+        t.join()
+        hosts.append( t.result )
+    return hosts
+
+def getAllPorts( main ):
+    """
+        Return a list containing the ports output from each ONOS node
+    """
+    ports = []
+    threads = []
+    for i in range( main.numCtrls ):
+        t = main.Thread( target=main.CLIs[i].ports,
+                         name="ports-" + str( i ),
+                         args=[ ] )
+        threads.append( t )
+        t.start()
+
+    for t in threads:
+        t.join()
+        ports.append( t.result )
+    return ports
+
+def getAllLinks( main ):
+    """
+        Return a list containing the links output from each ONOS node
+    """
+    links = []
+    threads = []
+    for i in range( main.numCtrls ):
+        t = main.Thread( target=main.CLIs[i].links,
+                         name="links-" + str( i ),
+                         args=[ ] )
+        threads.append( t )
+        t.start()
+
+    for t in threads:
+        t.join()
+        links.append( t.result )
+    return links
+
+def getAllClusters( main ):
+    """
+        Return a list containing the clusters output from each ONOS node
+    """
+    clusters = []
+    threads = []
+    for i in range( main.numCtrls ):
+        t = main.Thread( target=main.CLIs[i].clusters,
+                         name="clusters-" + str( i ),
+                         args=[ ] )
+        threads.append( t )
+        t.start()
+
+    for t in threads:
+        t.join()
+        clusters.append( t.result )
+    return clusters
+
+