Initial implementation of ONOS cluster driver

- Create CLI, REST, and "Bench" components for a cluster
- Return driver object when it is created
- Add __str__ and __repr__ implementations for drivers
- Add first pass at a cluster class
- Prototype with clustered Sample test
- Prototype with HAsanity test
- Add new Exception class for SkipCase

Change-Id: I32ee7cf655ab9a2a5cfccf5f891ca71a6a70c1ee
diff --git a/TestON/tests/SAMP/SAMPstartTemplate_3node/SAMPstartTemplate_3node.params b/TestON/tests/SAMP/SAMPstartTemplate_3node/SAMPstartTemplate_3node.params
index 99996dd..fe36d6e 100755
--- a/TestON/tests/SAMP/SAMPstartTemplate_3node/SAMPstartTemplate_3node.params
+++ b/TestON/tests/SAMP/SAMPstartTemplate_3node/SAMPstartTemplate_3node.params
@@ -1,26 +1,12 @@
 <PARAMS>
     <!--
         CASE0: pull onos code - this case should be skipped on Jenkins-driven prod test
-    -->
-    <!--
         CASE1: setup and clean test env
-    -->
-    <!--
         CASE2: get onos warnings, errors from log
-    -->
-    <!--
         CASE10: start a 3-node ONOS Cluster
-    -->
-    <!--
         CASE11: Start Mininet and assign controllers
-    -->
-    <!--
         CASE12: Sample case of using onos cli
-    -->
-    <!--
         CASE22: Sample case of using onos rest
-    -->
-   <!--
         CASE32: Configure fwd apps
    -->
 
@@ -36,7 +22,6 @@
     </CASE0>
 
     <CASE1>
-        <NodeList>OC1,OC2,OC3</NodeList>
         <SleepTimers>
             <onosStartup>60</onosStartup>
             <onosCfg>5</onosCfg>
@@ -46,7 +31,6 @@
     </CASE1>
 
     <CASE10>
-        <numNodes>3</numNodes>
         <Apps>
             org.onosproject.openflow,org.onosproject.fwd
         </Apps>
diff --git a/TestON/tests/SAMP/SAMPstartTemplate_3node/SAMPstartTemplate_3node.py b/TestON/tests/SAMP/SAMPstartTemplate_3node/SAMPstartTemplate_3node.py
index e2e63ec..ac5e8b5 100644
--- a/TestON/tests/SAMP/SAMPstartTemplate_3node/SAMPstartTemplate_3node.py
+++ b/TestON/tests/SAMP/SAMPstartTemplate_3node/SAMPstartTemplate_3node.py
@@ -56,10 +56,12 @@
         '''
         try:
             from tests.dependencies.ONOSSetup import ONOSSetup
+            from dependencies.Cluster import Cluster
         except ImportError:
             main.log.error( "ONOSSetup not found. exiting the test" )
             main.exit()
         try:
+            main.Cluster = Cluster( main.ONOScell.nodes )
             main.testSetUp
         except ( NameError, AttributeError ):
             main.testSetUp = ONOSSetup()
@@ -79,12 +81,14 @@
         main.testSetUp.evnSetupConclusion( stepResult )
 
 
+
     def CASE2( self, main ):
         '''
             Report errors/warnings/exceptions
         '''
         main.log.info("Error report: \n" )
-        main.ONOSbench.logReport( main.ONOSip[0],
+        ONOSbench = main.ONOScell.nodes[0].Bench
+        ONOSbench.logReport( main.Cluster.controllers[0].ipAddress,
                                   [ "INFO",
                                     "FOLLOWER",
                                     "WARN",
@@ -112,10 +116,12 @@
 
         import time
 
-        main.case( "Start up " + str( main.numCtrls ) + "-node onos cluster.")
+        size = len( main.Cluster.controllers )
+        main.case( "Start up " + str( size ) + "-node onos cluster." )
+
         main.step( "Start ONOS cluster with basic (drivers) app.")
-        stepResult = main.ONOSbench.startBasicONOS( nodeList=main.ONOSip, opSleep=200,
-                                                    onosUser=main.ONOScli1.karafUser )
+        stepResult = ONOSbench.startBasicONOS( nodeList=main.Cluster.getIps(), opSleep=200,
+                                               onosUser=main.ONOScell.karafUser )
         utilities.assert_equals( expect=main.TRUE,
                                  actual=stepResult,
                                  onpass="Successfully started basic ONOS cluster ",
@@ -135,9 +141,9 @@
         else:
             main.log.warn( "No configurations were specified to be changed after startup" )
         utilities.assert_equals( expect=main.TRUE,
-                                     actual=activateResult,
-                                     onpass="Successfully set config",
-                                     onfail="Failed to set config" )
+                                 actual=activateResult,
+                                 onpass="Successfully set config",
+                                 onfail="Failed to set config" )
 
         main.step( "Set ONOS configurations" )
         config = main.params['CASE10'].get( 'ONOS_Configuration' )
@@ -147,7 +153,7 @@
             for component in config:
                 for setting in config[component]:
                     value = config[component][setting]
-                    check = main.ONOScli1.setCfg( component, setting, value )
+                    check = main.Cluster.controllers[0].setCfg( component, setting, value )
                     main.log.info( "Value was changed? {}".format( main.TRUE == check ) )
                     checkResult = check and checkResult
             utilities.assert_equals( expect=main.TRUE,
@@ -183,8 +189,8 @@
         assignResult = main.TRUE
         for i in range(1, 8):
             assignResult = assignResult & main.Mininet1.assignSwController( sw="s" + str( i ),
-                                                         ip=main.ONOSip,
-                                                         port='6653' )
+                                                                            ip=main.Cluster.getIps(),
+                                                                            port='6653' )
         time.sleep(main.mnCfgSleep)
         utilities.assert_equals( expect=main.TRUE,
                                  actual=stepResult,
@@ -198,8 +204,8 @@
         """
 
         main.case( "Test some onos commands through CLI. ")
-        main.log.debug( main.ONOScli1.sendline("summary") )
-        main.log.debug( main.ONOScli3.sendline("devices") )
+        main.log.debug( main.Cluster.controllers[1].sendline("summary") )
+        main.log.debug( main.Cluster.controllers[2].sendline("devices") )
 
     def CASE22( self, main ):
         """
@@ -207,8 +213,8 @@
         """
 
         main.case( " Sample tests using ONOS REST API handles. ")
-        main.log.debug( main.ONOSrest1.send("/devices") )
-        main.log.debug( main.ONOSrest2.apps() )
+        main.log.debug( main.Cluster.controllers[2].send("/devices") )
+        main.log.debug( main.Cluster.controllers[-1].apps() )
 
     def CASE32( self, main ):
         """
@@ -219,7 +225,7 @@
         """
         main.case( "Configure onos-app-fwd and check if configuration successful. " )
         main.step( "Install reactive forwarding app." )
-        installResults = main.ONOScli1.activateApp( "org.onosproject.fwd" )
+        installResults = main.Cluster.controllers[0].activateApp( "org.onosproject.fwd" )
         utilities.assert_equals( expect=main.TRUE, actual=installResults,
                                  onpass= "Configure fwd successful", onfail= "Configure fwd failed" )
         main.step( "Run pingall to check connectivity. " )
diff --git a/TestON/tests/SAMP/SAMPstartTemplate_3node/SAMPstartTemplate_3node.topo b/TestON/tests/SAMP/SAMPstartTemplate_3node/SAMPstartTemplate_3node.topo
index 9d8298e..5ab7af6 100755
--- a/TestON/tests/SAMP/SAMPstartTemplate_3node/SAMPstartTemplate_3node.topo
+++ b/TestON/tests/SAMP/SAMPstartTemplate_3node/SAMPstartTemplate_3node.topo
@@ -5,99 +5,36 @@
         Even with some handles not used in test cases, we want to define
         all onos cells here, for cases to set up onos cluster.
     -->
-        <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>
-                <home></home> #defines where onos home is
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSbench>
-
-        <ONOScli1>
-            <host>localhost</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'
                 <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>localhost</host>
-            <user>sdn</user>
-            <password>rocks</password>
-            <type>OnosCliDriver</type>
-            <connect_order>3</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOScli2>
-
-         <ONOScli3>
-            <host>localhost</host>
-            <user>sdn</user>
-            <password>rocks</password>
-            <type>OnosCliDriver</type>
-            <connect_order>4</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOScli3>
+        </ONOScell>
 
         <Mininet1>
             <host>OCN</host>
             <user>sdn</user>
             <password>rocks</password>
             <type>MininetCliDriver</type>
-            <connect_order>5</connect_order>
+            <connect_order>3</connect_order>
             <COMPONENTS>
                 <home>~/mininet/custom/</home>
             </COMPONENTS>
         </Mininet1>
 
-        <ONOSrest1>
-            <host>OC1</host>
-            <port>8181</port>
-            <user>onos</user>
-            <password>rocks</password>
-            <type>OnosRestDriver</type>
-            <connect_order>6</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>7</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>8</connect_order>
-            <COMPONENTS>
-                <prompt></prompt>
-            </COMPONENTS>
-        </ONOSrest3>
 
     </COMPONENT>
 </TOPOLOGY>