Update Cluster Driver

Change-Id: I8a3a57e19637ff210548e57d41178e6f194cf694
diff --git a/TestON/tests/USECASE/SegmentRouting/SRClusterRestart/SRClusterRestart.py b/TestON/tests/USECASE/SegmentRouting/SRClusterRestart/SRClusterRestart.py
index dda8e41..5735c9d 100755
--- a/TestON/tests/USECASE/SegmentRouting/SRClusterRestart/SRClusterRestart.py
+++ b/TestON/tests/USECASE/SegmentRouting/SRClusterRestart/SRClusterRestart.py
@@ -42,7 +42,7 @@
         if not hasattr( main, 'apps' ):
             run.initTest( main )
         main.cfgName = '2x2'
-        main.numCtrls = 3
+        main.Cluster.setRunningNode( 3 )
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py' )
         # pre-configured routing and bridging test
@@ -75,7 +75,7 @@
         if not hasattr( main, 'apps' ):
             run.initTest( main )
         main.cfgName = '4x4'
-        main.numCtrls = 3
+        main.Cluster.setRunningNode( 3 )
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py', args="--leaf=4 --spine=4" )
         # pre-configured routing and bridging test
@@ -108,7 +108,7 @@
         if not hasattr( main, 'apps' ):
             run.initTest( main )
         main.cfgName = '0x1'
-        main.numCtrls = 3
+        main.Cluster.setRunningNode( 3 )
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py', args="--leaf=1 --spine=0" )
         # pre-configured routing and bridging test
diff --git a/TestON/tests/USECASE/SegmentRouting/SRClusterRestart/SRClusterRestart.topo b/TestON/tests/USECASE/SegmentRouting/SRClusterRestart/SRClusterRestart.topo
index 4d4ce2d..f6661f8 100755
--- a/TestON/tests/USECASE/SegmentRouting/SRClusterRestart/SRClusterRestart.topo
+++ b/TestON/tests/USECASE/SegmentRouting/SRClusterRestart/SRClusterRestart.topo
@@ -1,95 +1,32 @@
 <TOPOLOGY>
     <COMPONENT>
 
-        <ONOSbench>
-            <host>localhost</host>
+        <ONOScell>
+            <host>localhost</host>  # ONOS "bench" machine
             <user>sdn</user>
             <password>rocks</password>
-            <type>OnosDriver</type>
+            <type>OnosClusterDriver</type>
             <connect_order>1</connect_order>
             <COMPONENTS>
-                <nodes>3</nodes>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSbench>
-
-        <ONOScli1>
-            <host>OC1</host>
-            <user>sdn</user>
-            <password>rocks</password>
-            <type>OnosCliDriver</type>
-            <connect_order>2</connect_order>
-            <COMPONENTS>
+                <cluster_name></cluster_name>  # Used as a prefix for cluster components. Defaults to 'ONOS'
+                <diff_clihost>True</diff_clihost> # if it has different host other than localhost for CLI. True or empty. OC# will be used if True.
                 <karaf_username></karaf_username>
                 <karaf_password></karaf_password>
-                <prompt></prompt>
+                <web_user></web_user>
+                <web_pass></web_pass>
+                <rest_port></rest_port>
+                <prompt></prompt>  # TODO: we technically need a few of these, one per component
+                <onos_home></onos_home>  # defines where onos home is
+                <nodes> 3 </nodes>  # number of nodes in the cluster
             </COMPONENTS>
-        </ONOScli1>
-        
-        <ONOScli2>
-            <host>OC2</host>
-            <user>sdn</user>
-            <password>rocks</password>
-            <type>OnosCliDriver</type>
-            <connect_order>3</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOScli2>
-
-        <ONOScli3>
-            <host>OC3</host>
-            <user>sdn</user>
-            <password>rocks</password>
-            <type>OnosCliDriver</type>
-            <connect_order>4</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOScli3>
-
-        <ONOSrest1>
-            <host>OC1</host>
-            <port>8181</port>
-            <user>onos</user>
-            <password>rocks</password>
-            <type>OnosRestDriver</type>
-            <connect_order>5</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSrest1>
-
-        <ONOSrest2>
-            <host>OC2</host>
-            <port>8181</port>
-            <user>onos</user>
-            <password>rocks</password>
-            <type>OnosRestDriver</type>
-            <connect_order>6</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSrest2>
-
-        <ONOSrest3>
-            <host>OC3</host>
-            <port>8181</port>
-            <user>onos</user>
-            <password>rocks</password>
-            <type>OnosRestDriver</type>
-            <connect_order>6</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSrest3>
+        </ONOScell>
 
         <Mininet1>
             <host>OCN</host>
             <user>sdn</user>
             <password>rocks</password>
             <type>MininetCliDriver</type>
-            <connect_order>7</connect_order>
+            <connect_order>2</connect_order>
             <COMPONENTS>
                 <home>~/mininet/custom/</home>
                 <prompt></prompt>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRDynamic/SRDynamic.py b/TestON/tests/USECASE/SegmentRouting/SRDynamic/SRDynamic.py
index 432f4ba..44f704e 100755
--- a/TestON/tests/USECASE/SegmentRouting/SRDynamic/SRDynamic.py
+++ b/TestON/tests/USECASE/SegmentRouting/SRDynamic/SRDynamic.py
@@ -45,7 +45,7 @@
         main.case( description )
 
         main.cfgName = '2x2'
-        main.numCtrls = 1
+        main.Cluster.setRunningNode( 1 )
         run.installOnos( main, vlanCfg=False )
         run.startMininet( main, 'cord_fabric.py' )
         # pre-configured routing and bridging test
@@ -69,7 +69,7 @@
         description = "Bridging and Routing sanity test with 4x4 Leaf-spine "
         main.case( description )
         main.cfgName = '4x4'
-        main.numCtrls = 1
+        main.Cluster.setRunningNode( 1 )
         run.installOnos( main, vlanCfg=False )
         run.startMininet( main, 'cord_fabric.py',
                           args="--leaf=4 --spine=4" )
@@ -94,7 +94,7 @@
         description = "Bridging and Routing sanity test with single switch "
         main.case( description )
         main.cfgName = '0x1'
-        main.numCtrls = 1
+        main.Cluster.setRunningNode( 1 )
         run.installOnos( main, vlanCfg=False )
         run.startMininet( main, 'cord_fabric.py',
                           args="--leaf=1 --spine=0" )
@@ -120,7 +120,7 @@
         main.case( description )
 
         main.cfgName = '2x2'
-        main.numCtrls = 3
+        main.Cluster.setRunningNode( 3 )
         run.installOnos( main, vlanCfg=False )
         run.startMininet( main, 'cord_fabric.py' )
         # pre-configured routing and bridging test
@@ -148,7 +148,7 @@
         description = "Bridging and Routing sanity test with 4x4 Leaf-spine "
         main.case( description )
         main.cfgName = '4x4'
-        main.numCtrls = 3
+        main.Cluster.setRunningNode( 3 )
         run.installOnos( main, vlanCfg=False )
         run.startMininet( main, 'cord_fabric.py',
                           args="--leaf=4 --spine=4" )
@@ -177,7 +177,7 @@
         description = "Bridging and Routing sanity test with single switch "
         main.case( description )
         main.cfgName = '0x1'
-        main.numCtrls = 3
+        main.Cluster.setRunningNode( 3 )
         run.installOnos( main, vlanCfg=False )
         run.startMininet( main, 'cord_fabric.py',
                           args="--leaf=1 --spine=0" )
diff --git a/TestON/tests/USECASE/SegmentRouting/SRDynamic/SRDynamic.topo b/TestON/tests/USECASE/SegmentRouting/SRDynamic/SRDynamic.topo
index 4d4ce2d..f6661f8 100755
--- a/TestON/tests/USECASE/SegmentRouting/SRDynamic/SRDynamic.topo
+++ b/TestON/tests/USECASE/SegmentRouting/SRDynamic/SRDynamic.topo
@@ -1,95 +1,32 @@
 <TOPOLOGY>
     <COMPONENT>
 
-        <ONOSbench>
-            <host>localhost</host>
+        <ONOScell>
+            <host>localhost</host>  # ONOS "bench" machine
             <user>sdn</user>
             <password>rocks</password>
-            <type>OnosDriver</type>
+            <type>OnosClusterDriver</type>
             <connect_order>1</connect_order>
             <COMPONENTS>
-                <nodes>3</nodes>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSbench>
-
-        <ONOScli1>
-            <host>OC1</host>
-            <user>sdn</user>
-            <password>rocks</password>
-            <type>OnosCliDriver</type>
-            <connect_order>2</connect_order>
-            <COMPONENTS>
+                <cluster_name></cluster_name>  # Used as a prefix for cluster components. Defaults to 'ONOS'
+                <diff_clihost>True</diff_clihost> # if it has different host other than localhost for CLI. True or empty. OC# will be used if True.
                 <karaf_username></karaf_username>
                 <karaf_password></karaf_password>
-                <prompt></prompt>
+                <web_user></web_user>
+                <web_pass></web_pass>
+                <rest_port></rest_port>
+                <prompt></prompt>  # TODO: we technically need a few of these, one per component
+                <onos_home></onos_home>  # defines where onos home is
+                <nodes> 3 </nodes>  # number of nodes in the cluster
             </COMPONENTS>
-        </ONOScli1>
-        
-        <ONOScli2>
-            <host>OC2</host>
-            <user>sdn</user>
-            <password>rocks</password>
-            <type>OnosCliDriver</type>
-            <connect_order>3</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOScli2>
-
-        <ONOScli3>
-            <host>OC3</host>
-            <user>sdn</user>
-            <password>rocks</password>
-            <type>OnosCliDriver</type>
-            <connect_order>4</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOScli3>
-
-        <ONOSrest1>
-            <host>OC1</host>
-            <port>8181</port>
-            <user>onos</user>
-            <password>rocks</password>
-            <type>OnosRestDriver</type>
-            <connect_order>5</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSrest1>
-
-        <ONOSrest2>
-            <host>OC2</host>
-            <port>8181</port>
-            <user>onos</user>
-            <password>rocks</password>
-            <type>OnosRestDriver</type>
-            <connect_order>6</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSrest2>
-
-        <ONOSrest3>
-            <host>OC3</host>
-            <port>8181</port>
-            <user>onos</user>
-            <password>rocks</password>
-            <type>OnosRestDriver</type>
-            <connect_order>6</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSrest3>
+        </ONOScell>
 
         <Mininet1>
             <host>OCN</host>
             <user>sdn</user>
             <password>rocks</password>
             <type>MininetCliDriver</type>
-            <connect_order>7</connect_order>
+            <connect_order>2</connect_order>
             <COMPONENTS>
                 <home>~/mininet/custom/</home>
                 <prompt></prompt>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRHighAvailability/SRHighAvailability.py b/TestON/tests/USECASE/SegmentRouting/SRHighAvailability/SRHighAvailability.py
index 7e3565e..ba0242d 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRHighAvailability/SRHighAvailability.py
+++ b/TestON/tests/USECASE/SegmentRouting/SRHighAvailability/SRHighAvailability.py
@@ -52,14 +52,14 @@
 
         description = "High Availability tests - ONOS failures with 2x2 Leaf-spine "
         main.case( description )
-        run.config(main, '2x2', 3)
+        run.config(main, '2x2')
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py' )
         # pre-configured routing and bridging test
         run.checkFlows( main, minFlowCount=116 )
         run.pingAll( main )
         for i in range(0, main.failures):
-            toKill = i % main.numCtrls
+            toKill = i % main.Cluster.numCtrls
             run.killOnos( main, [ toKill ], '4', '8', '2' )
             run.pingAll( main, 'CASE1_Failure%d' % (i+1) )
             run.recoverOnos( main, [ toKill ], '4', '8', '3' )
@@ -86,7 +86,7 @@
 
         description = "High Availability tests - ONOS random failures with 2x2 Leaf-spine "
         main.case( description )
-        run.config(main, '2x2', 3)
+        run.config(main, '2x2')
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py' )
         # pre-configured routing and bridging test
@@ -94,7 +94,7 @@
         run.pingAll( main )
         random.seed(datetime.now())
         for i in range(0, main.failures):
-            toKill = randint(0, (main.numCtrls-1))
+            toKill = randint( 0, ( main.Cluster.numCtrls - 1 ) )
             run.killOnos( main, [ toKill ], '4', '8', '2' )
             run.pingAll( main, 'CASE2_Failure%d' % (i+1) )
             run.recoverOnos( main, [ toKill ], '4', '8', '3' )
@@ -118,14 +118,14 @@
 
         description = "High Availability tests - ONOS failures with 4x4 Leaf-spine "
         main.case( description )
-        run.config(main, '4x4', 3)
+        run.config(main, '4x4')
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py', args="--leaf=4 --spine=4" )
         # pre-configured routing and bridging test
         run.checkFlows( main, minFlowCount=350 )
         run.pingAll( main )
         for i in range(0, main.failures):
-            toKill = i % main.numCtrls
+            toKill = i % main.Cluster.numCtrls
             run.killOnos( main, [ toKill ], '8', '32', '2' )
             run.pingAll( main, 'CASE3_Failure%d' % (i+1) )
             run.recoverOnos( main, [ toKill ], '8', '32', '3' )
@@ -152,7 +152,7 @@
 
         description = "High Availability tests - ONOS random failures with 4x4 Leaf-spine "
         main.case( description )
-        run.config(main, '4x4', 3)
+        run.config(main, '4x4')
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py', args="--leaf=4 --spine=4" )
         # pre-configured routing and bridging test
@@ -160,7 +160,7 @@
         run.pingAll( main )
         random.seed(datetime.now())
         for i in range(0, main.failures):
-            toKill = randint(0, (main.numCtrls-1))
+            toKill = randint( 0, ( main.Cluster.numCtrls - 1 ) )
             run.killOnos( main, [ toKill ], '8', '32', '2' )
             run.pingAll( main, 'CASE4_Failure%d' % (i+1) )
             run.recoverOnos( main, [ toKill ], '8', '32', '3' )
@@ -187,14 +187,14 @@
 
         description = "High Availability tests - ONOS failures and Switch failures with 2x2 Leaf-spine "
         main.case( description )
-        run.config(main, '2x2', 3)
+        run.config(main, '2x2')
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py' )
         # pre-configured routing and bridging test
         run.checkFlows( main, minFlowCount=116 )
         run.pingAll( main )
         for i in range(0, main.failures):
-            onosToKill = i % main.numCtrls
+            onosToKill = i % main.Cluster.numCtrls
             switchToKill = i % len(main.spines)
             run.killOnos( main, [ onosToKill ], '4', '8', '2' )
             run.pingAll( main, 'CASE5_ONOS_Failure%d' % (i+1) )
@@ -231,14 +231,14 @@
 
         description = "High Availability tests - ONOS random failures and Switch random failures with 2x2 Leaf-spine "
         main.case( description )
-        run.config(main, '2x2', 3)
+        run.config(main, '2x2')
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py' )
         # pre-configured routing and bridging test
         run.checkFlows( main, minFlowCount=116 )
         run.pingAll( main )
         for i in range(0, main.failures):
-            onosToKill = randint(0, (main.numCtrls-1))
+            onosToKill = randint( 0, ( main.Cluster.numCtrls - 1 ) )
             switchToKill = randint(0, 1)
             run.killOnos( main, [ onosToKill ], '4', '8', '2' )
             run.pingAll( main, 'CASE6_ONOS_Failure%d' % (i+1) )
@@ -272,14 +272,14 @@
 
         description = "High Availability tests - ONOS failures and Switch failures with 4x4 Leaf-spine "
         main.case( description )
-        run.config(main, '4x4', 3)
+        run.config(main, '4x4')
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py', args="--leaf=4 --spine=4" )
         # pre-configured routing and bridging test
         run.checkFlows( main, minFlowCount=350 )
         run.pingAll( main )
         for i in range(0, main.failures):
-            onosToKill = i % main.numCtrls
+            onosToKill = i % main.Cluster.numCtrls
             switchToKill = i % len(main.spines)
             run.killOnos( main, [ onosToKill ], '8', '32', '2' )
             run.pingAll( main, 'CASE7_ONOS_Failure%d' % (i+1) )
@@ -316,14 +316,14 @@
 
         description = "High Availability tests - ONOS random failures and Switch random failures with 4x4 Leaf-spine "
         main.case( description )
-        run.config(main, '4x4', 3)
+        run.config(main, '4x4')
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py', args="--leaf=4 --spine=4" )
         # pre-configured routing and bridging test
         run.checkFlows( main, minFlowCount=350 )
         run.pingAll( main )
         for i in range(0, main.failures):
-            onosToKill = randint(0, (main.numCtrls-1))
+            onosToKill = randint( 0, ( main.Cluster.numCtrls - 1 ) )
             switchToKill = randint(0, 3)
             run.killOnos( main, [ onosToKill ], '8', '32', '2' )
             run.pingAll( main, 'CASE8_ONOS_Failure%d' % (i+1) )
diff --git a/TestON/tests/USECASE/SegmentRouting/SRHighAvailability/SRHighAvailability.topo b/TestON/tests/USECASE/SegmentRouting/SRHighAvailability/SRHighAvailability.topo
index 6c83bb2..f6661f8 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRHighAvailability/SRHighAvailability.topo
+++ b/TestON/tests/USECASE/SegmentRouting/SRHighAvailability/SRHighAvailability.topo
@@ -1,95 +1,32 @@
 <TOPOLOGY>
     <COMPONENT>
 
-        <ONOSbench>
-            <host>localhost</host>
+        <ONOScell>
+            <host>localhost</host>  # ONOS "bench" machine
             <user>sdn</user>
             <password>rocks</password>
-            <type>OnosDriver</type>
+            <type>OnosClusterDriver</type>
             <connect_order>1</connect_order>
             <COMPONENTS>
-                <nodes>3</nodes>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSbench>
-
-        <ONOScli1>
-            <host>OC1</host>
-            <user>sdn</user>
-            <password>rocks</password>
-            <type>OnosCliDriver</type>
-            <connect_order>2</connect_order>
-            <COMPONENTS>
+                <cluster_name></cluster_name>  # Used as a prefix for cluster components. Defaults to 'ONOS'
+                <diff_clihost>True</diff_clihost> # if it has different host other than localhost for CLI. True or empty. OC# will be used if True.
                 <karaf_username></karaf_username>
                 <karaf_password></karaf_password>
-                <prompt></prompt>
+                <web_user></web_user>
+                <web_pass></web_pass>
+                <rest_port></rest_port>
+                <prompt></prompt>  # TODO: we technically need a few of these, one per component
+                <onos_home></onos_home>  # defines where onos home is
+                <nodes> 3 </nodes>  # number of nodes in the cluster
             </COMPONENTS>
-        </ONOScli1>
-
-        <ONOScli2>
-            <host>OC2</host>
-            <user>sdn</user>
-            <password>rocks</password>
-            <type>OnosCliDriver</type>
-            <connect_order>3</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOScli2>
-
-        <ONOScli3>
-            <host>OC3</host>
-            <user>sdn</user>
-            <password>rocks</password>
-            <type>OnosCliDriver</type>
-            <connect_order>4</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOScli3>
-
-        <ONOSrest1>
-            <host>OC1</host>
-            <port>8181</port>
-            <user>onos</user>
-            <password>rocks</password>
-            <type>OnosRestDriver</type>
-            <connect_order>5</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSrest1>
-
-        <ONOSrest2>
-            <host>OC2</host>
-            <port>8181</port>
-            <user>onos</user>
-            <password>rocks</password>
-            <type>OnosRestDriver</type>
-            <connect_order>6</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSrest2>
-
-        <ONOSrest3>
-            <host>OC3</host>
-            <port>8181</port>
-            <user>onos</user>
-            <password>rocks</password>
-            <type>OnosRestDriver</type>
-            <connect_order>7</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSrest3>
+        </ONOScell>
 
         <Mininet1>
             <host>OCN</host>
             <user>sdn</user>
             <password>rocks</password>
             <type>MininetCliDriver</type>
-            <connect_order>7</connect_order>
+            <connect_order>2</connect_order>
             <COMPONENTS>
                 <home>~/mininet/custom/</home>
                 <prompt></prompt>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRLinkFailure/SRLinkFailure.py b/TestON/tests/USECASE/SegmentRouting/SRLinkFailure/SRLinkFailure.py
index 98c0d8d..cb95b18 100755
--- a/TestON/tests/USECASE/SegmentRouting/SRLinkFailure/SRLinkFailure.py
+++ b/TestON/tests/USECASE/SegmentRouting/SRLinkFailure/SRLinkFailure.py
@@ -46,7 +46,7 @@
         main.case( description )
 
         main.cfgName = '2x2'
-        main.numCtrls = 1
+        main.Cluster.setRunningNode( 1 )
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py' )
         # pre-configured routing and bridging test
@@ -80,7 +80,7 @@
         description = "Bridging and Routing sanity test with 4x4 Leaf-spine "
         main.case( description )
         main.cfgName = '4x4'
-        main.numCtrls = 1
+        main.Cluster.setRunningNode( 1 )
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py', args="--leaf=4 --spine=4" )
         # pre-configured routing and bridging test
@@ -114,7 +114,7 @@
         description = "Bridging and Routing sanity test with 2x2 Leaf-spine "
         main.case( description )
         main.cfgName = '2x2'
-        main.numCtrls = 3
+        main.Cluster.setRunningNode( 3 )
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py' )
         # pre-configured routing and bridging test
@@ -148,7 +148,7 @@
         description = "Bridging and Routing sanity test with 4x4 Leaf-spine "
         main.case( description )
         main.cfgName = '4x4'
-        main.numCtrls = 3
+        main.Cluster.setRunningNode( 3 )
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py', args="--leaf=4 --spine=4" )
         # pre-configured routing and bridging test
diff --git a/TestON/tests/USECASE/SegmentRouting/SRLinkFailure/SRLinkFailure.topo b/TestON/tests/USECASE/SegmentRouting/SRLinkFailure/SRLinkFailure.topo
index 28c6820..f6661f8 100755
--- a/TestON/tests/USECASE/SegmentRouting/SRLinkFailure/SRLinkFailure.topo
+++ b/TestON/tests/USECASE/SegmentRouting/SRLinkFailure/SRLinkFailure.topo
@@ -1,94 +1,32 @@
 <TOPOLOGY>
     <COMPONENT>
 
-        <ONOSbench>
-            <host>localhost</host>
+        <ONOScell>
+            <host>localhost</host>  # ONOS "bench" machine
             <user>sdn</user>
             <password>rocks</password>
-            <type>OnosDriver</type>
+            <type>OnosClusterDriver</type>
             <connect_order>1</connect_order>
             <COMPONENTS>
-                <nodes>3</nodes>
-            </COMPONENTS>
-        </ONOSbench>
-
-        <ONOScli1>
-            <host>OC1</host>
-            <user>sdn</user>
-            <password>rocks</password>
-            <type>OnosCliDriver</type>
-            <connect_order>2</connect_order>
-            <COMPONENTS>
+                <cluster_name></cluster_name>  # Used as a prefix for cluster components. Defaults to 'ONOS'
+                <diff_clihost>True</diff_clihost> # if it has different host other than localhost for CLI. True or empty. OC# will be used if True.
                 <karaf_username></karaf_username>
                 <karaf_password></karaf_password>
-                <prompt></prompt>
+                <web_user></web_user>
+                <web_pass></web_pass>
+                <rest_port></rest_port>
+                <prompt></prompt>  # TODO: we technically need a few of these, one per component
+                <onos_home></onos_home>  # defines where onos home is
+                <nodes> 3 </nodes>  # number of nodes in the cluster
             </COMPONENTS>
-        </ONOScli1>
-
-        <ONOScli2>
-            <host>OC2</host>
-            <user>sdn</user>
-            <password>rocks</password>
-            <type>OnosCliDriver</type>
-            <connect_order>3</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOScli2>
-
-        <ONOScli3>
-            <host>OC3</host>
-            <user>sdn</user>
-            <password>rocks</password>
-            <type>OnosCliDriver</type>
-            <connect_order>4</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOScli3>
-
-        <ONOSrest1>
-            <host>OC1</host>
-            <port>8181</port>
-            <user>onos</user>
-            <password>rocks</password>
-            <type>OnosRestDriver</type>
-            <connect_order>5</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSrest1>
-
-        <ONOSrest2>
-            <host>OC2</host>
-            <port>8181</port>
-            <user>onos</user>
-            <password>rocks</password>
-            <type>OnosRestDriver</type>
-            <connect_order>6</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSrest2>
-
-        <ONOSrest3>
-            <host>OC3</host>
-            <port>8181</port>
-            <user>onos</user>
-            <password>rocks</password>
-            <type>OnosRestDriver</type>
-            <connect_order>7</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSrest3>
+        </ONOScell>
 
         <Mininet1>
             <host>OCN</host>
             <user>sdn</user>
             <password>rocks</password>
             <type>MininetCliDriver</type>
-            <connect_order>8</connect_order>
+            <connect_order>2</connect_order>
             <COMPONENTS>
                 <home>~/mininet/custom/</home>
                 <prompt></prompt>
diff --git a/TestON/tests/USECASE/SegmentRouting/SROnosFailure/SROnosFailure.py b/TestON/tests/USECASE/SegmentRouting/SROnosFailure/SROnosFailure.py
index d5c35a8..f0383ae 100755
--- a/TestON/tests/USECASE/SegmentRouting/SROnosFailure/SROnosFailure.py
+++ b/TestON/tests/USECASE/SegmentRouting/SROnosFailure/SROnosFailure.py
@@ -42,7 +42,7 @@
         if not hasattr( main, 'apps' ):
             run.initTest( main )
         main.cfgName = '2x2'
-        main.numCtrls = 3
+        main.Cluster.setRunningNode( 3 )
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py' )
         # pre-configured routing and bridging test
@@ -75,7 +75,7 @@
         if not hasattr( main, 'apps' ):
             run.initTest( main )
         main.cfgName = '4x4'
-        main.numCtrls = 3
+        main.Cluster.setRunningNode( 3 )
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py', args="--leaf=4 --spine=4" )
         # pre-configured routing and bridging test
@@ -108,7 +108,7 @@
         if not hasattr( main, 'apps' ):
             run.initTest( main )
         main.cfgName = '0x1'
-        main.numCtrls = 3
+        main.Cluster.setRunningNode( 3 )
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py', args="--leaf=1 --spine=0" )
         # pre-configured routing and bridging test
diff --git a/TestON/tests/USECASE/SegmentRouting/SROnosFailure/SROnosFailure.topo b/TestON/tests/USECASE/SegmentRouting/SROnosFailure/SROnosFailure.topo
index 4d4ce2d..e0b1d43 100755
--- a/TestON/tests/USECASE/SegmentRouting/SROnosFailure/SROnosFailure.topo
+++ b/TestON/tests/USECASE/SegmentRouting/SROnosFailure/SROnosFailure.topo
@@ -1,95 +1,32 @@
 <TOPOLOGY>
     <COMPONENT>
 
-        <ONOSbench>
-            <host>localhost</host>
+        <ONOScell>
+            <host>localhost</host>  # ONOS "bench" machine
             <user>sdn</user>
             <password>rocks</password>
-            <type>OnosDriver</type>
+            <type>OnosClusterDriver</type>
             <connect_order>1</connect_order>
             <COMPONENTS>
-                <nodes>3</nodes>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSbench>
-
-        <ONOScli1>
-            <host>OC1</host>
-            <user>sdn</user>
-            <password>rocks</password>
-            <type>OnosCliDriver</type>
-            <connect_order>2</connect_order>
-            <COMPONENTS>
+                <cluster_name></cluster_name>  # Used as a prefix for cluster components. Defaults to 'ONOS'
+                <diff_clihost>True</diff_clihost> # if it has different host other than localhost for CLI. True or empty. OC# will be used if True.
                 <karaf_username></karaf_username>
                 <karaf_password></karaf_password>
-                <prompt></prompt>
+                <web_user></web_user>
+                <web_pass></web_pass>
+                <rest_port></rest_port>
+                <prompt></prompt>  # TODO: we technically need a few of these, one per component
+                <onos_home></onos_home>  # defines where onos home is
+                <nodes> 3 </nodes>  # number of nodes in the cluster
             </COMPONENTS>
-        </ONOScli1>
-        
-        <ONOScli2>
-            <host>OC2</host>
-            <user>sdn</user>
-            <password>rocks</password>
-            <type>OnosCliDriver</type>
-            <connect_order>3</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOScli2>
-
-        <ONOScli3>
-            <host>OC3</host>
-            <user>sdn</user>
-            <password>rocks</password>
-            <type>OnosCliDriver</type>
-            <connect_order>4</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOScli3>
-
-        <ONOSrest1>
-            <host>OC1</host>
-            <port>8181</port>
-            <user>onos</user>
-            <password>rocks</password>
-            <type>OnosRestDriver</type>
-            <connect_order>5</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSrest1>
-
-        <ONOSrest2>
-            <host>OC2</host>
-            <port>8181</port>
-            <user>onos</user>
-            <password>rocks</password>
-            <type>OnosRestDriver</type>
-            <connect_order>6</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSrest2>
-
-        <ONOSrest3>
-            <host>OC3</host>
-            <port>8181</port>
-            <user>onos</user>
-            <password>rocks</password>
-            <type>OnosRestDriver</type>
-            <connect_order>6</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSrest3>
+        </ONOScell>
 
         <Mininet1>
             <host>OCN</host>
             <user>sdn</user>
             <password>rocks</password>
             <type>MininetCliDriver</type>
-            <connect_order>7</connect_order>
+            <connect_order>2</connect_order>
             <COMPONENTS>
                 <home>~/mininet/custom/</home>
                 <prompt></prompt>
@@ -97,4 +34,4 @@
         </Mininet1>
 
     </COMPONENT>
-</TOPOLOGY>
+</TOPOLOGY>
\ No newline at end of file
diff --git a/TestON/tests/USECASE/SegmentRouting/SRSanity/SRSanity.py b/TestON/tests/USECASE/SegmentRouting/SRSanity/SRSanity.py
index 1e8cedd..435683e 100755
--- a/TestON/tests/USECASE/SegmentRouting/SRSanity/SRSanity.py
+++ b/TestON/tests/USECASE/SegmentRouting/SRSanity/SRSanity.py
@@ -45,7 +45,7 @@
         main.case( description )
 
         main.cfgName = '2x2'
-        main.numCtrls = 1
+        main.Cluster.setRunningNode( 1 )
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py' )
         # pre-configured routing and bridging test
@@ -71,7 +71,7 @@
         description = "Bridging and Routing sanity test with 4x4 Leaf-spine "
         main.case( description )
         main.cfgName = '4x4'
-        main.numCtrls = 1
+        main.Cluster.setRunningNode( 1 )
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py', args="--leaf=4 --spine=4" )
         # pre-configured routing and bridging test
@@ -123,7 +123,7 @@
         description = "Bridging and Routing sanity test with 2x2 Leaf-spine "
         main.case( description )
         main.cfgName = '2x2'
-        main.numCtrls = 3
+        main.Cluster.setRunningNode( 3 )
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py' )
         # pre-configured routing and bridging test
@@ -149,7 +149,7 @@
         description = "Bridging and Routing sanity test with 4x4 Leaf-spine "
         main.case( description )
         main.cfgName = '4x4'
-        main.numCtrls = 3
+        main.Cluster.setRunningNode( 3 )
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py', args="--leaf=4 --spine=4" )
         # pre-configured routing and bridging test
@@ -175,7 +175,7 @@
         description = "Bridging and Routing sanity test with single switch "
         main.case( description )
         main.cfgName = '0x1'
-        main.numCtrls = 3
+        main.Cluster.setRunningNode( 3 )
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py', args="--leaf=1 --spine=0" )
         # pre-configured routing and bridging test
diff --git a/TestON/tests/USECASE/SegmentRouting/SRSanity/SRSanity.topo b/TestON/tests/USECASE/SegmentRouting/SRSanity/SRSanity.topo
index 4d4ce2d..e0b1d43 100755
--- a/TestON/tests/USECASE/SegmentRouting/SRSanity/SRSanity.topo
+++ b/TestON/tests/USECASE/SegmentRouting/SRSanity/SRSanity.topo
@@ -1,95 +1,32 @@
 <TOPOLOGY>
     <COMPONENT>
 
-        <ONOSbench>
-            <host>localhost</host>
+        <ONOScell>
+            <host>localhost</host>  # ONOS "bench" machine
             <user>sdn</user>
             <password>rocks</password>
-            <type>OnosDriver</type>
+            <type>OnosClusterDriver</type>
             <connect_order>1</connect_order>
             <COMPONENTS>
-                <nodes>3</nodes>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSbench>
-
-        <ONOScli1>
-            <host>OC1</host>
-            <user>sdn</user>
-            <password>rocks</password>
-            <type>OnosCliDriver</type>
-            <connect_order>2</connect_order>
-            <COMPONENTS>
+                <cluster_name></cluster_name>  # Used as a prefix for cluster components. Defaults to 'ONOS'
+                <diff_clihost>True</diff_clihost> # if it has different host other than localhost for CLI. True or empty. OC# will be used if True.
                 <karaf_username></karaf_username>
                 <karaf_password></karaf_password>
-                <prompt></prompt>
+                <web_user></web_user>
+                <web_pass></web_pass>
+                <rest_port></rest_port>
+                <prompt></prompt>  # TODO: we technically need a few of these, one per component
+                <onos_home></onos_home>  # defines where onos home is
+                <nodes> 3 </nodes>  # number of nodes in the cluster
             </COMPONENTS>
-        </ONOScli1>
-        
-        <ONOScli2>
-            <host>OC2</host>
-            <user>sdn</user>
-            <password>rocks</password>
-            <type>OnosCliDriver</type>
-            <connect_order>3</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOScli2>
-
-        <ONOScli3>
-            <host>OC3</host>
-            <user>sdn</user>
-            <password>rocks</password>
-            <type>OnosCliDriver</type>
-            <connect_order>4</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOScli3>
-
-        <ONOSrest1>
-            <host>OC1</host>
-            <port>8181</port>
-            <user>onos</user>
-            <password>rocks</password>
-            <type>OnosRestDriver</type>
-            <connect_order>5</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSrest1>
-
-        <ONOSrest2>
-            <host>OC2</host>
-            <port>8181</port>
-            <user>onos</user>
-            <password>rocks</password>
-            <type>OnosRestDriver</type>
-            <connect_order>6</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSrest2>
-
-        <ONOSrest3>
-            <host>OC3</host>
-            <port>8181</port>
-            <user>onos</user>
-            <password>rocks</password>
-            <type>OnosRestDriver</type>
-            <connect_order>6</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSrest3>
+        </ONOScell>
 
         <Mininet1>
             <host>OCN</host>
             <user>sdn</user>
             <password>rocks</password>
             <type>MininetCliDriver</type>
-            <connect_order>7</connect_order>
+            <connect_order>2</connect_order>
             <COMPONENTS>
                 <home>~/mininet/custom/</home>
                 <prompt></prompt>
@@ -97,4 +34,4 @@
         </Mininet1>
 
     </COMPONENT>
-</TOPOLOGY>
+</TOPOLOGY>
\ No newline at end of file
diff --git a/TestON/tests/USECASE/SegmentRouting/SRSwitchFailure/SRSwitchFailure.py b/TestON/tests/USECASE/SegmentRouting/SRSwitchFailure/SRSwitchFailure.py
index fefca29..1b0968c 100755
--- a/TestON/tests/USECASE/SegmentRouting/SRSwitchFailure/SRSwitchFailure.py
+++ b/TestON/tests/USECASE/SegmentRouting/SRSwitchFailure/SRSwitchFailure.py
@@ -46,7 +46,7 @@
         main.case( description )
 
         main.cfgName = '2x2'
-        main.numCtrls = 1
+        main.Cluster.setRunningNode( 1 )
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py' )
         # pre-configured routing and bridging test
@@ -82,7 +82,7 @@
         description = "Bridging and Routing sanity test with 4x4 Leaf-spine "
         main.case( description )
         main.cfgName = '4x4'
-        main.numCtrls = 1
+        main.Cluster.setRunningNode( 1 )
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py', args="--leaf=4 --spine=4" )
         # pre-configured routing and bridging test
@@ -118,7 +118,7 @@
         description = "Bridging and Routing sanity test with 2x2 Leaf-spine "
         main.case( description )
         main.cfgName = '2x2'
-        main.numCtrls = 3
+        main.Cluster.setRunningNode( 3 )
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py' )
         # pre-configured routing and bridging test
@@ -154,7 +154,7 @@
         description = "Bridging and Routing sanity test with 4x4 Leaf-spine "
         main.case( description )
         main.cfgName = '4x4'
-        main.numCtrls = 3
+        main.Cluster.setRunningNode( 3 )
         run.installOnos( main )
         run.startMininet( main, 'cord_fabric.py', args="--leaf=4 --spine=4" )
         # pre-configured routing and bridging test
diff --git a/TestON/tests/USECASE/SegmentRouting/SRSwitchFailure/SRSwitchFailure.topo b/TestON/tests/USECASE/SegmentRouting/SRSwitchFailure/SRSwitchFailure.topo
index b4b41ee..ee6ce56 100755
--- a/TestON/tests/USECASE/SegmentRouting/SRSwitchFailure/SRSwitchFailure.topo
+++ b/TestON/tests/USECASE/SegmentRouting/SRSwitchFailure/SRSwitchFailure.topo
@@ -1,95 +1,32 @@
 <TOPOLOGY>
     <COMPONENT>
 
-        <ONOSbench>
-            <host>localhost</host>
+        <ONOScell>
+            <host>localhost</host>  # ONOS "bench" machine
             <user>sdn</user>
             <password>rocks</password>
-            <type>OnosDriver</type>
+            <type>OnosClusterDriver</type>
             <connect_order>1</connect_order>
             <COMPONENTS>
-                <nodes>3</nodes>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSbench>
-
-        <ONOScli1>
-            <host>OC1</host>
-            <user>sdn</user>
-            <password>rocks</password>
-            <type>OnosCliDriver</type>
-            <connect_order>2</connect_order>
-            <COMPONENTS>
+                <cluster_name></cluster_name>  # Used as a prefix for cluster components. Defaults to 'ONOS'
+                <diff_clihost>True</diff_clihost> # if it has different host other than localhost for CLI. True or empty. OC# will be used for True.
                 <karaf_username></karaf_username>
                 <karaf_password></karaf_password>
-                <prompt></prompt>
+                <web_user></web_user>
+                <web_pass></web_pass>
+                <rest_port></rest_port>
+                <prompt></prompt>  # TODO: we technically need a few of these, one per component
+                <onos_home></onos_home>  # defines where onos home is
+                <nodes> 3 </nodes>  # number of nodes in the cluster
             </COMPONENTS>
-        </ONOScli1>
-
-        <ONOScli2>
-            <host>OC2</host>
-            <user>sdn</user>
-            <password>rocks</password>
-            <type>OnosCliDriver</type>
-            <connect_order>3</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOScli2>
-
-        <ONOScli3>
-            <host>OC3</host>
-            <user>sdn</user>
-            <password>rocks</password>
-            <type>OnosCliDriver</type>
-            <connect_order>4</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOScli3>
-
-        <ONOSrest1>
-            <host>OC1</host>
-            <port>8181</port>
-            <user>onos</user>
-            <password>rocks</password>
-            <type>OnosRestDriver</type>
-            <connect_order>5</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSrest1>
-
-        <ONOSrest2>
-            <host>OC2</host>
-            <port>8181</port>
-            <user>onos</user>
-            <password>rocks</password>
-            <type>OnosRestDriver</type>
-            <connect_order>6</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSrest2>
-
-        <ONOSrest3>
-            <host>OC3</host>
-            <port>8181</port>
-            <user>onos</user>
-            <password>rocks</password>
-            <type>OnosRestDriver</type>
-            <connect_order>7</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSrest3>
+        </ONOScell>
 
         <Mininet1>
             <host>OCN</host>
             <user>sdn</user>
             <password>rocks</password>
             <type>MininetCliDriver</type>
-            <connect_order>8</connect_order>
+            <connect_order>2</connect_order>
             <COMPONENTS>
                 <home>~/mininet/custom/</home>
                 <prompt></prompt>
diff --git a/TestON/tests/USECASE/SegmentRouting/dependencies/Testcaselib.py b/TestON/tests/USECASE/SegmentRouting/dependencies/Testcaselib.py
index c9d52d3..38dbaf6 100755
--- a/TestON/tests/USECASE/SegmentRouting/dependencies/Testcaselib.py
+++ b/TestON/tests/USECASE/SegmentRouting/dependencies/Testcaselib.py
@@ -71,7 +71,7 @@
                                               main.topology,
                                               main.Mininet1.home,
                                               direction="to" )
-            stepResult = main.testSetUp.envSetup( hasRest=True )
+            stepResult = main.testSetUp.envSetup()
         except Exception as e:
             main.testSetUp.envSetupException( e )
         main.testSetUp.evnSetupConclusion( stepResult )
@@ -96,51 +96,51 @@
             main.apps = main.apps + "," + main.diff
         else:
             main.log.error( "App list is empty" )
-        print "NODE COUNT = ", main.numCtrls
-        print main.ONOSip
+        main.log.info( "NODE COUNT = " + str( main.Cluster.numCtrls ) )
+        main.log.info( ''.join( main.Cluster.getIps() ) )
         main.dynamicHosts = [ 'in1', 'out1' ]
-        main.testSetUp.createApplyCell( newCell=True, cellName=main.cellName,
-                                        Mininet=main.Mininet1, useSSH=Testcaselib.useSSH )
+        main.testSetUp.createApplyCell( main.Cluster, newCell=True, cellName=main.cellName,
+                                        Mininet=main.Mininet1, useSSH=Testcaselib.useSSH,
+                                        ip=main.Cluster.getIps() )
         # 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 ] )
+        for ctrl in main.Cluster.runningNodes:
+            main.ONOSbench.onosDie( ctrl.ipAddress )
 
-        main.testSetUp.buildOnos()
+        main.testSetUp.buildOnos( main.Cluster )
 
-        main.testSetUp.installOnos( False )
+        main.testSetUp.installOnos( main.Cluster, False )
 
-        main.testSetUp.setupSsh()
+        main.testSetUp.setupSsh( main.Cluster )
 
-        main.testSetUp.checkOnosService()
+        main.testSetUp.checkOnosService( main.Cluster )
 
+        cliResult = main.TRUE
         main.step( "Checking if ONOS CLI is ready" )
-        for i in range( main.numCtrls ):
-            main.CLIs[ i ].startCellCli( )
-            cliResult = main.CLIs[ i ].startOnosCli( main.ONOSip[ i ],
-                                                     commandlineTimeout=60,
-                                                     onosStartTimeout=100 )
+        for ctrl in main.Cluster.runningNodes:
+            ctrl.CLI.startCellCli( )
+            cliResult = cliResult and ctrl.CLI.startOnosCli( ctrl.ipAddress,
+                                                             commandlineTimeout=60,
+                                                             onosStartTimeout=100 )
+            ctrl.active = True
         utilities.assert_equals( expect=main.TRUE,
                                  actual=cliResult,
                                  onpass="ONOS CLI is ready",
                                  onfail="ONOS CLI is not ready" )
-        main.active = 0
-        for i in range( 10 ):
-            ready = True
-            output = main.CLIs[ main.active ].summary()
-            if not output:
-                ready = False
-            if ready:
-                break
-            time.sleep( 10 )
-        utilities.assert_equals( expect=True, actual=ready,
+        ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
+                                 main.FALSE,
+                                 sleep=10,
+                                 attempts=10 )
+        if ready:
+            ready = main.TRUE
+        utilities.assert_equals( expect=main.TRUE, actual=ready,
                                  onpass="ONOS summary command succeded",
                                  onfail="ONOS summary command failed" )
 
         with open( "%s/json/%s.json" % (
                 main.dependencyPath, main.cfgName) ) as cfg:
-            main.RESTs[ main.active ].setNetCfg( json.load( cfg ) )
+            main.Cluster.active( 0 ).REST.setNetCfg( json.load( cfg ) )
         with open( "%s/json/%s.chart" % (
                 main.dependencyPath, main.cfgName) ) as chart:
             main.pingChart = json.load( chart )
@@ -149,17 +149,16 @@
             main.cleanup( )
             main.exit( )
 
-        for i in range( main.numCtrls ):
-            main.CLIs[ i ].logSet( "DEBUG", "org.onosproject.segmentrouting" )
-            main.CLIs[ i ].logSet( "DEBUG", "org.onosproject.driver.pipeline" )
-            main.CLIs[ i ].logSet( "DEBUG", "org.onosproject.store.group.impl" )
-            main.CLIs[ i ].logSet( "DEBUG",
-                                   "org.onosproject.net.flowobjective.impl" )
+        for ctrl in main.Cluster.active():
+            ctrl.CLI.logSet( "DEBUG", "org.onosproject.segmentrouting" )
+            ctrl.CLI.logSet( "DEBUG", "org.onosproject.driver.pipeline" )
+            ctrl.CLI.logSet( "DEBUG", "org.onosproject.store.group.impl" )
+            ctrl.CLI.logSet( "DEBUG", "org.onosproject.net.flowobjective.impl" )
 
     @staticmethod
     def startMininet( main, topology, args="" ):
         main.step( "Starting Mininet Topology" )
-        arg = "--onos %d %s" % (main.numCtrls, args)
+        arg = "--onos %d %s" % (main.Cluster.numCtrls, args)
         main.topology = topology
         topoResult = main.Mininet1.startNet(
                 topoFile=main.Mininet1.home + main.topology, args=arg )
@@ -174,12 +173,11 @@
             main.exit( )
 
     @staticmethod
-    def config(main, cfgName, numCtrls):
+    def config( main, cfgName ):
         main.spines     = []
 
         main.failures   = int(main.params[ 'failures' ])
         main.cfgName    = cfgName
-        main.numCtrls   = numCtrls
 
         if main.cfgName == '2x2' :
             spine           = {}
@@ -222,7 +220,7 @@
     def checkFlows( main, minFlowCount, dumpflows=True ):
         main.step(
                 " Check whether the flow count is bigger than %s" % minFlowCount )
-        count = utilities.retry( main.CLIs[ main.active ].checkFlowCount,
+        count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowCount,
                                  main.FALSE,
                                  kwargs={ 'min': minFlowCount },
                                  attempts=10,
@@ -234,7 +232,7 @@
                 onfail="Flow count looks wrong: " + str( count ) )
 
         main.step( "Check whether all flow status are ADDED" )
-        flowCheck = utilities.retry( main.CLIs[ main.active ].checkFlowsState,
+        flowCheck = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowsState,
                                      main.FALSE,
                                      kwargs={ 'isPENDING': False },
                                      attempts=2,
@@ -245,11 +243,11 @@
                 onpass="Flow status is correct!",
                 onfail="Flow status is wrong!" )
         if dumpflows:
-            main.ONOSbench.dumpONOSCmd( main.ONOSip[ main.active ],
+            main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
                                         "flows",
                                         main.logdir,
                                         "flowsBefore" + main.cfgName )
-            main.ONOSbench.dumpONOSCmd( main.ONOSip[ main.active ],
+            main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
                                         "groups",
                                         main.logdir,
                                         "groupsBefore" + main.cfgName )
@@ -268,11 +266,11 @@
                                      onpass="IP connectivity successfully tested",
                                      onfail="IP connectivity failed" )
         if dumpflows:
-            main.ONOSbench.dumpONOSCmd( main.ONOSip[ main.active ],
+            main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
                                         "flows",
                                         main.logdir,
                                         "flowsOn" + tag )
-            main.ONOSbench.dumpONOSCmd( main.ONOSip[ main.active ],
+            main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
                                         "groups",
                                         main.logdir,
                                         "groupsOn" + tag )
@@ -291,7 +289,7 @@
         main.log.info(
                 "Waiting %s seconds for link down to be discovered" % main.linkSleep )
         time.sleep( main.linkSleep )
-        topology = utilities.retry( main.CLIs[ main.active ].checkStatus,
+        topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
                                     main.FALSE,
                                     kwargs={ 'numoswitch': switches,
                                              'numolink': links },
@@ -324,15 +322,16 @@
                     "Waiting %s seconds for link up to be discovered" % main.linkSleep )
             time.sleep( main.linkSleep )
 
-            for i in range(0, main.numCtrls):
-                onosIsUp = main.ONOSbench.isup( main.ONOSip[ i ] )
+            for i in range(0, main.Cluster.numCtrls):
+                ctrl = main.Cluster.runningNodes[ i ]
+                onosIsUp = main.ONOSbench.isup( ctrl.ipAddress )
                 if onosIsUp == main.TRUE:
-                    main.CLIs[ i ].portstate( dpid=dpid1, port=port1 )
-                    main.CLIs[ i ].portstate( dpid=dpid2, port=port2 )
+                    ctrl.CLI.portstate( dpid=dpid1, port=port1 )
+                    ctrl.CLI.portstate( dpid=dpid2, port=port2 )
             time.sleep( main.linkSleep )
 
-            result = main.CLIs[ main.active ].checkStatus( numoswitch=switches,
-                                                           numolink=links )
+            result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
+                                                               numolink=links )
             if count > 5 or result:
                 break
         utilities.assert_equals( expect=main.TRUE, actual=result,
@@ -353,7 +352,7 @@
         main.log.info( "Waiting %s seconds for switch down to be discovered" % (
             main.switchSleep) )
         time.sleep( main.switchSleep )
-        topology = utilities.retry( main.CLIs[ main.active ].checkStatus,
+        topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
                                     main.FALSE,
                                     kwargs={ 'numoswitch': switches,
                                              'numolink': links },
@@ -376,7 +375,7 @@
         main.log.info( "Waiting %s seconds for switch up to be discovered" % (
             main.switchSleep) )
         time.sleep( main.switchSleep )
-        topology = utilities.retry( main.CLIs[ main.active ].checkStatus,
+        topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
                                     main.FALSE,
                                     kwargs={ 'numoswitch': switches,
                                              'numolink': links },
@@ -399,16 +398,16 @@
             main.log.error( "Utils not found exiting the test" )
             main.exit()
         try:
-            main.Utils
+            main.utils
         except ( NameError, AttributeError ):
-            main.Utils = Utils()
+            main.utils = Utils()
 
         main.utils.mininetCleanup( main.Mininet1 )
 
-        main.utils.copyKarafLog()
+        main.utils.copyKarafLog( main.cfgName )
 
-        for i in range( main.numCtrls ):
-            main.ONOSbench.onosStop( main.ONOSip[ i ] )
+        for ctrl in main.Cluster.active():
+            main.ONOSbench.onosStop( ctrl.ipAddress )
 
     @staticmethod
     def killOnos( main, nodes, switches, links, expNodes ):
@@ -421,23 +420,17 @@
         main.step( "Killing ONOS instance" )
 
         for i in nodes:
-            killResult = main.ONOSbench.onosDie( main.CLIs[ i ].ip_address )
+            killResult = main.ONOSbench.onosDie( main.Cluster.runningNodes[ i ].ipAddress )
             utilities.assert_equals( expect=main.TRUE, actual=killResult,
                                      onpass="ONOS instance Killed",
                                      onfail="Error killing ONOS instance" )
-            if i == main.active:
-                main.active = (i + 1) % main.numCtrls
+            main.Cluster.runningNodes[ i ].active = False
         time.sleep( 12 )
 
-        if len( nodes ) < main.numCtrls:
+        if len( nodes ) < main.Cluster.numCtrls:
 
-            nodesToCheck = []
-            for x in range(0, main.numCtrls):
-                if x not in nodes:
-                    nodesToCheck.append(x)
             nodeResults = utilities.retry( Testcaselib.nodesCheck,
                                            False,
-                                           args=[nodesToCheck],
                                            attempts=5,
                                            sleep=10 )
             utilities.assert_equals( expect=True, actual=nodeResults,
@@ -446,15 +439,15 @@
 
             if not nodeResults:
                 for i in nodes:
-                    cli = main.CLIs[i]
+                    ctrl = main.Cluster.runningNodes[ i ]
                     main.log.debug( "{} components not ACTIVE: \n{}".format(
-                        cli.name,
-                        cli.sendline( "scr:list | grep -v ACTIVE" ) ) )
+                        ctrl.name,
+                        ctrl.CLI.sendline( "scr:list | grep -v ACTIVE" ) ) )
                 main.log.error( "Failed to kill ONOS, stopping test" )
                 main.cleanup()
                 main.exit()
 
-            topology = utilities.retry( main.CLIs[ main.active ].checkStatus,
+            topology = utilities.retry( main.Cluster.active( 0 ).checkStatus,
                                         main.FALSE,
                                         kwargs={ 'numoswitch': switches,
                                                  'numolink': links,
@@ -464,8 +457,6 @@
             utilities.assert_equals( expect=main.TRUE, actual=topology,
                                      onpass="ONOS Instance down successful",
                                      onfail="Failed to turn off ONOS Instance" )
-        else:
-            main.active = -1
 
     @staticmethod
     def recoverOnos( main, nodes, switches, links, expNodes ):
@@ -475,23 +466,24 @@
         Recover an ONOS instance and verify the ONOS cluster can see the proper change
         """
         main.step( "Recovering ONOS instance" )
-        [ main.ONOSbench.onosStart( main.CLIs[ i ].ip_address ) for i in nodes ]
+        [ main.ONOSbench.onosStart( main.Cluster.runningNodes[ i ].ipAddress ) for i in nodes ]
         for i in nodes:
-            isUp = main.ONOSbench.isup( main.ONOSip[ i ] )
+            isUp = main.ONOSbench.isup( main.Cluster.runningNodes[ i ].ipAddress )
             utilities.assert_equals( expect=main.TRUE, actual=isUp,
                                      onpass="ONOS service is ready",
                                      onfail="ONOS service did not start properly" )
         for i in nodes:
             main.step( "Checking if ONOS CLI is ready" )
-            main.CLIs[ i ].startCellCli( )
-            cliResult = main.CLIs[ i ].startOnosCli( main.ONOSip[ i ],
-                                                     commandlineTimeout=60,
-                                                     onosStartTimeout=100 )
+            ctrl = main.Cluster.runningNodes[ i ]
+            ctrl.CLI.startCellCli()
+            cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
+                                               commandlineTimeout=60,
+                                               onosStartTimeout=100 )
+            ctrl.active = True
             utilities.assert_equals( expect=main.TRUE,
                                      actual=cliResult,
                                      onpass="ONOS CLI is ready",
                                      onfail="ONOS CLI is not ready" )
-            main.active = i if main.active == -1 else main.active
 
         main.step( "Checking ONOS nodes" )
         nodeResults = utilities.retry( Testcaselib.nodesCheck,
@@ -505,15 +497,15 @@
 
         if not nodeResults:
             for i in nodes:
-                cli = main.CLIs[i]
+                ctrl = main.Cluster.runningNodes[ i ]
                 main.log.debug( "{} components not ACTIVE: \n{}".format(
-                    cli.name,
-                    cli.sendline( "scr:list | grep -v ACTIVE" ) ) )
+                    ctrl.name,
+                    ctrl.CLI.sendline( "scr:list | grep -v ACTIVE" ) ) )
             main.log.error( "Failed to start ONOS, stopping test" )
             main.cleanup()
             main.exit()
 
-        topology = utilities.retry( main.CLIs[ main.active ].checkStatus,
+        topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
                                     main.FALSE,
                                     kwargs={ 'numoswitch': switches,
                                              'numolink': links,
@@ -523,15 +515,13 @@
         utilities.assert_equals( expect=main.TRUE, actual=topology,
                                  onpass="ONOS Instance down successful",
                                  onfail="Failed to turn off ONOS Instance" )
-        for i in range( 10 ):
-            ready = True
-            output = main.CLIs[ main.active ].summary( )
-            if not output:
-                ready = False
-            if ready:
-                break
-            time.sleep( 10 )
-        utilities.assert_equals( expect=True, actual=ready,
+        ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
+                                 main.FALSE,
+                                 attempts=10,
+                                 sleep=12 )
+        if ready:
+            ready = main.TRUE
+        utilities.assert_equals( expect=main.TRUE, actual=ready,
                                  onpass="ONOS summary command succeded",
                                  onfail="ONOS summary command failed" )
         if not ready:
@@ -552,18 +542,18 @@
         main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
         main.step( "Pushing new configuration" )
         mac, cfg = hostCfg[ 'hosts' ].popitem( )
-        main.RESTs[ main.active ].setNetCfg( cfg[ 'basic' ],
-                                             subjectClass="hosts",
-                                             subjectKey=urllib.quote( mac,
-                                                                      safe='' ),
-                                             configKey="basic" )
+        main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
+                                                 subjectClass="hosts",
+                                                 subjectKey=urllib.quote( mac,
+                                                                          safe='' ),
+                                                 configKey="basic" )
         main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
         main.step( "Pushing new configuration" )
         mac, cfg = hostCfg[ 'hosts' ].popitem( )
-        main.RESTs[ main.active ].setNetCfg( cfg[ 'basic' ],
-                                             subjectClass="hosts",
-                                             subjectKey=urllib.quote( mac,
-                                                                      safe='' ),
+        main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
+                                                 subjectClass="hosts",
+                                                 subjectKey=urllib.quote( mac,
+                                                                          safe='' ),
                                              configKey="basic" )
         main.pingChart.update( { 'vlan1': { "expect": "True",
                                             "hosts": [ "olt1", "vsg1" ] } } )
@@ -571,10 +561,10 @@
         main.pingChart[ 'vlan10' ][ 'expect' ] = 0
         ports = "[%s,%s]" % (5, 6)
         cfg = '{"of:0000000000000001":[{"vlan":1,"ports":%s,"name":"OLT 1"}]}' % ports
-        main.RESTs[ main.active ].setNetCfg( json.loads( cfg ),
-                                             subjectClass="apps",
-                                             subjectKey="org.onosproject.segmentrouting",
-                                             configKey="xconnect" )
+        main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
+                                                 subjectClass="apps",
+                                                 subjectKey="org.onosproject.segmentrouting",
+                                                 configKey="xconnect" )
 
     @staticmethod
     def delHostCfg( main ):
@@ -589,40 +579,29 @@
         main.step( "Removing host configuration" )
         main.pingChart[ 'ip' ][ 'expect' ] = 0
         mac, cfg = hostCfg[ 'hosts' ].popitem( )
-        main.RESTs[ main.active ].removeNetCfg( subjectClass="hosts",
-                                                subjectKey=urllib.quote(
-                                                        mac,
-                                                        safe='' ),
-                                                configKey="basic" )
+        main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
+                                                    subjectKey=urllib.quote(
+                                                            mac,
+                                                            safe='' ),
+                                                    configKey="basic" )
         main.step( "Removing configuration" )
         main.pingChart[ 'ip' ][ 'expect' ] = 0
         mac, cfg = hostCfg[ 'hosts' ].popitem( )
-        main.RESTs[ main.active ].removeNetCfg( subjectClass="hosts",
-                                                subjectKey=urllib.quote(
-                                                        mac,
-                                                        safe='' ),
-                                                configKey="basic" )
+        main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
+                                                    subjectKey=urllib.quote(
+                                                            mac,
+                                                            safe='' ),
+                                                    configKey="basic" )
         main.step( "Removing vlan configuration" )
         main.pingChart[ 'vlan1' ][ 'expect' ] = 0
-        main.RESTs[ main.active ].removeNetCfg( subjectClass="apps",
-                                                subjectKey="org.onosproject.segmentrouting",
-                                                configKey="xconnect" )
+        main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="apps",
+                                                    subjectKey="org.onosproject.segmentrouting",
+                                                    configKey="xconnect" )
     @staticmethod
     def nodesCheck( nodes ):
-        nodesOutput = []
         results = True
-        threads = []
-        for i in nodes:
-            t = main.Thread( target=main.CLIs[i].nodes,
-                             name="nodes-" + str( i ),
-                             args=[ ] )
-            threads.append( t )
-            t.start()
-
-        for t in threads:
-            t.join()
-            nodesOutput.append( t.result )
-        ips = [ main.ONOSip[ node ] for node in nodes ]
+        nodesOutput = main.Cluster.command( "nodes", specificDriver=2 )
+        ips = main.Cluster.getIps( activeOnly=True )
         ips.sort()
         for i in nodesOutput:
             try: