Cherry-pick from https://gerrit.onos.onlab.us/#/c/68/

Revise onos.py for ramcloud branch

issue: ONOS-959

Conflicts:

	start-rest.sh

NOTE: The above conflict has been resolved by hand.
In the process, minor refactoring/editing was done
for consistency with the rest of the scripts:
ONOSDIR -> ONOS_HOME

NOTE2: Fixed few issues in file vm-utils/onos.py that are related
to RAMCloud:
 - Fixed the path to the RAMCloud ramcloud.conf configuration file
 - Fixed the path to the RAMCloud daemon.

NOTE3: Fixed the modules list as set in baseModule in file vm-utils/onos.py
to reflect the dev/ramcloud-new-datamodel list.

NOTE4: Changed the file permission of vm-utils/onos.py so it is executable.

Change-Id: I4e245f694f9ed4182b49410707d214a2d6a056de
diff --git a/start-onos.sh b/start-onos.sh
index 5e8af65..248954d 100755
--- a/start-onos.sh
+++ b/start-onos.sh
@@ -12,9 +12,9 @@
 ## Because the script change dir to $ONOS_HOME, we can set ONOS_LOGBACK and LOGDIR relative to $ONOS_HOME
 ONOS_LOGBACK=${ONOS_LOGBACK:-${ONOS_HOME}/logback.`hostname`.xml}
 LOGDIR=${ONOS_LOGDIR:-${ONOS_HOME}/onos-logs}
-
-ONOS_LOG="${LOGDIR}/onos.`hostname`.log"
-PCAP_LOG="${LOGDIR}/onos.`hostname`.pcap"
+LOGBASE=${ONOS_LOGBASE:-onos.`hostname`}
+ONOS_LOG="${LOGDIR}/${LOGBASE}.log"
+PCAP_LOG="${LOGDIR}/${LOGBASE}.pcap"
 LOGS="$ONOS_LOG $PCAP_LOG"
 
 ONOS_PROPS=${ONOS_PROPS:-${ONOS_HOME}/conf/onos.properties}
@@ -124,7 +124,7 @@
   echo $ONOS_HOME
   cd ${ONOS_HOME}
   pwd
-  java ${JVM_OPTS} -Dlogback.configurationFile=${ONOS_LOGBACK} -cp ${JAVA_CP} ${MAIN_CLASS} -cf ${ONOS_PROPS} > ${LOGDIR}/onos.`hostname`.stdout 2>${LOGDIR}/onos.`hostname`.stderr &
+  java ${JVM_OPTS} -Dlogback.configurationFile=${ONOS_LOGBACK} -cp ${JAVA_CP} ${MAIN_CLASS} -cf ${ONOS_PROPS} > ${LOGDIR}/${LOGBASE}.stdout 2>${LOGDIR}/${LOGBASE}.stderr &
 
   echo "Waiting for ONOS to start..."
   COUNT=0
@@ -179,7 +179,7 @@
     start
     ;;
   startnokill)
-    check_db
+#    check_db
     start
     ;;
   startifdown)
diff --git a/start-ramcloud-coordinator.sh b/start-ramcloud-coordinator.sh
index 3bd3e39..fd1ec83 100755
--- a/start-ramcloud-coordinator.sh
+++ b/start-ramcloud-coordinator.sh
@@ -4,7 +4,7 @@
 # Set paths
 ONOS_HOME=`dirname $0`
 RAMCLOUD_DIR=${HOME}/ramcloud
-LOGDIR=${ONOS_HOME}/onos-logs
+LOGDIR=${ONOS_LOGDIR:-${ONOS_HOME}/onos-logs}
 RAMCLOUD_LOG=${LOGDIR}/ramcloud.coordinator.`hostname`.log
 coordinatorip=`grep coordinatorIp ${ONOS_HOME}/conf/ramcloud.conf | cut -d "=" -f 2,3`
 coordinatorport=`grep coordinatorPort ${ONOS_HOME}/conf/ramcloud.conf | cut -d "=" -f 2,3`
diff --git a/start-ramcloud-server.sh b/start-ramcloud-server.sh
index 0158be2..939543a 100755
--- a/start-ramcloud-server.sh
+++ b/start-ramcloud-server.sh
@@ -5,7 +5,7 @@
 # Set paths
 ONOS_HOME=`dirname $0`
 RAMCLOUD_DIR=${HOME}/ramcloud
-LOGDIR=${ONOS_HOME}/onos-logs
+LOGDIR=${ONOS_LOGDIR:-${ONOS_HOME}/onos-logs}
 RAMCLOUD_LOG=${LOGDIR}/ramcloud.server.`hostname`.log
 coordinatorip=`grep coordinatorIp ${ONOS_HOME}/conf/ramcloud.conf | cut -d "=" -f 2,3`
 coordinatorport=`grep coordinatorPort ${ONOS_HOME}/conf/ramcloud.conf | cut -d "=" -f 2,3`
diff --git a/start-rest.sh b/start-rest.sh
index a79a415..92a14da 100755
--- a/start-rest.sh
+++ b/start-rest.sh
@@ -1,13 +1,13 @@
 #! /bin/bash
 
 # Change this accordingly
-ONOSDIR=${ONOS_HOME:-${HOME}/ONOS}
+ONOS_HOME=${ONOS_HOME:-${HOME}/ONOS}
 script_name="topology_rest.py"
 
 #######################
-WEBDIR=${ONOSDIR}/web
+WEBDIR=${ONOS_HOME}/web
 restscript=${WEBDIR}/$script_name
-LOGDIR=${ONOS_LOGDIR:-${ONOSDIR}/onos-logs}
+LOGDIR=${ONOS_LOGDIR:-${ONOS_HOME}/onos-logs}
 REST_LOG="${LOGDIR}/rest.`hostname`.log"
 #######################
 
diff --git a/vm-utils/onos.py b/vm-utils/onos.py
index 7756b59..71a4e5d 100755
--- a/vm-utils/onos.py
+++ b/vm-utils/onos.py
@@ -8,7 +8,7 @@
 ONOSController: a custom Controller() subclass to start ONOS
 OVSSwitchONOS: a custom OVSSwitch() switch that connects to multiple controllers.
 
-We use single Zookeeper and Cassandra instances for now.
+We use single Zookeeper and Ramcloud instances for now.
 
 As a custom file, exports:
 
@@ -24,12 +24,12 @@
 $ sudo -E mn --custom onos.py --controller onos,2 --switch ovso
 """
 
-from mininet.node import Controller, OVSSwitch
+from mininet.node import Controller, OVSSwitch, CPULimitedHost, RemoteController
 from mininet.net import Mininet
 from mininet.cli import CLI
 from mininet.topo import LinearTopo
 from mininet.log import setLogLevel, info, warn
-from mininet.util import quietRun
+from mininet.util import quietRun, numCores
 
 # This should be cleaned up to avoid interfering with mn
 from shutil import copyfile
@@ -37,6 +37,7 @@
 from functools import partial
 import time
 from sys import argv
+from time import sleep
 
 class ONOS( Controller ):
     "Custom controller class for ONOS"
@@ -46,8 +47,7 @@
     onosDir = home + "/ONOS"
     zookeeperDir = home + "/zookeeper-3.4.5"
     dirBase = '/tmp'
-    logDir = dirBase + '/onos-%s.logs'
-    # cassDir = dirBase + '/onos-%s.cassandra'
+    logDir = dirBase + '/onos-logs'
     configFile = dirBase + '/onos-%s.properties'
     logbackFile = dirBase + '/onos-%s.logback.xml'
 
@@ -55,12 +55,14 @@
     baseModules = (
         'net.floodlightcontroller.core.FloodlightProvider',
         'net.floodlightcontroller.threadpool.ThreadPool',
-        'net.onrc.onos.ofcontroller.floodlightlistener.NetworkGraphPublisher',
+        'net.onrc.onos.ofcontroller.floodlightlistener.RCNetworkGraphPublisher',
         'net.floodlightcontroller.ui.web.StaticWebRoutable',
         'net.onrc.onos.datagrid.HazelcastDatagrid',
         'net.onrc.onos.ofcontroller.flowmanager.FlowManager',
         'net.onrc.onos.ofcontroller.flowprogrammer.FlowProgrammer',
         'net.onrc.onos.ofcontroller.topology.TopologyManager',
+        'net.onrc.onos.intent.runtime.PathCalcRuntimeModule',
+        'net.onrc.onos.intent.runtime.PlanInstallModule',
         'net.onrc.onos.registry.controller.ZookeeperRegistry'
     )
 
@@ -87,8 +89,8 @@
 
     # Things that are static
     staticConfig = {
-        'net.onrc.onos.ofcontroller.floodlightlistener.NetworkGraphPublisher.dbconf':
-            '/tmp/cassandra.titan',
+        'net.onrc.onos.ofcontroller.floodlightlistener.NetworkGraphPublisher.graph_db_store':
+            'ramcloud',
         'net.floodlightcontroller.core.FloodlightProvider.workerthreads': 16,
         'net.floodlightcontroller.forwarding.Forwarding.idletimeout': 5,
         'net.floodlightcontroller.forwarding.Forwarding.hardtimeout': 0
@@ -96,12 +98,18 @@
 
     # Things that are based on onosDir
     dirConfig = {
+        'net.onrc.onos.ofcontroller.floodlightlistener.NetworkGraphPublisher.dbconf':
+            '%s/conf/ramcloud.conf',
         'net.onrc.onos.datagrid.HazelcastDatagrid.datagridConfig':
         '%s/conf/hazelcast.xml',
     }
 
     proctag = 'mn-onos-id'
 
+    # List of scripts that we need/use
+    scripts = ( 'start-zk.sh', 'start-ramcloud-coordinator.sh',
+                'start-ramcloud-server.sh', 'start-onos.sh', 'start-rest.sh' )
+
     # For maven debugging
     # mvn = 'mvn -o -e -X'
 
@@ -115,6 +123,7 @@
         self.runAsRoot = runAsRoot
         self.ids = range( 0, self.count )
         Controller.__init__( self, name, **params )
+        self.proxies = []
         # We don't need to run as root, and it can interfere
         # with starting Zookeeper manually
         self.user = None
@@ -125,6 +134,7 @@
                 self.waiting = False
             except:
                 warn( '__init__: failed to drop privileges\n' )
+        self.cmd( 'mkdir -p', self.logDir )
         # Need to run commands from ONOS dir
         self.cmd( 'cd', self.onosDir )
         self.cmd( 'export PATH=$PATH:%s' % self.onosDir )
@@ -143,7 +153,7 @@
             self.onosDir = environ[ 'ONOS_HOME' ]
         else:
             warn( '* $ONOS_HOME is not set - assuming %s\n' % self.onosDir )
-        for script in 'start-zk.sh', 'start-cassandra.sh', 'start-onos.sh':
+        for script in self.scripts:
             script = path.join( self.onosDir, script )
             if not path.exists( script ):
                 msg = '%s not found' % script
@@ -156,37 +166,55 @@
            We assume that once a process is listening on some
            port, it is ready to go!"""
         while True:
-            output = self.cmd( 'sudo netstat -natp | grep %s/' % pid )
+            output = self.cmd( 'sudo netstat -natup | grep %s/' % pid )
             if output:
-                return output
+                break
             info( '.' )
             time.sleep( 1 )
+        info( '\n* Process %d is listening\n' % pid  )
 
-    def waitStart( self, procname, pattern ):
-        "Wait for at least one of procname to show up in netstat"
+    def waitStart( self, procname, pattern, maxWait=10 ):
+        "Wait for proces to start up and be visible to pgrep"
         # Check script exit code
         exitCode = int( self.cmd( 'echo $?' ) )
         if exitCode != 0:
             raise Exception( '%s startup failed with code %d' %
                              ( procname, exitCode ) )
         info( '* Waiting for %s startup' % procname )
-        result = self.cmd( 'pgrep -f %s' % pattern ).split()[ 0 ]
-        pid = int( result )
-        output = self.waitNetstat( pid )
-        info( '\n* %s process %d is listening\n' % ( procname, pid ) )
-        info( output )
+        while True:
+            result = self.cmd( 'pgrep -f %s' % pattern )
+            if result:
+                break
+            info( '.' )
+            sleep( 1 )
+        pid = int( result.split()[ 0 ] )
+        return pid
 
-    def startCassandra( self ):
-        "Start Cassandra"
-        self.cmd( 'start-cassandra.sh start' )
-        self.waitStart( 'Cassandra', 'apache-cassandra' )
-        status = self.cmd( 'start-cassandra.sh status' )
-        if 'running' not in status:
-            raise Exception( 'Cassandra startup failed: ' + status )
+    def startRamcloud( self, cpu=.6 ):
+        """Start Ramcloud
+           cpu: CPU usage limit (in seconds/s)"""
+        # Edit configuration file
+        self.cmd( "sed -ibak -e 's/host=.*/host=127.0.0.1/' %s/conf/ramcloud.conf" %
+            self.onosDir)
+        # Create a cgroup so Ramcloud doesn't eat all of our CPU
+        ramcloud = CPULimitedHost( 'ramcloud', inNamespace=False, period_us=5000 )
+        ramcloud.setCPUFrac( cpu / numCores() )
+        ramcloud.cmd( 'export PATH=%s:$PATH' % self.onosDir )
+        ramcloud.cmd( 'export ONOS_LOGDIR=%s' % self.logDir )
+        for daemon in 'coordinator', 'server':
+            ramcloud.cmd( 'start-ramcloud-%s.sh start' % daemon )
+            pid = self.waitStart( 'Ramcloud %s' % daemon, 'obj.master/' + daemon )
+            self.waitNetstat( pid )
+            status = self.cmd( 'start-ramcloud-%s.sh status' % daemon )
+            if 'running' not in status:
+                raise Exception( 'Ramcloud %s startup failed: ' % daemon + status )
+        self.ramcloud = ramcloud
 
-    def stopCassandra( self ):
-        "Stop Cassandra"
-        self.cmd( 'start-cassandra.sh stop' )
+    def stopRamcloud( self ):
+        "Stop Ramcloud"
+        for daemon in 'coordinator', 'server':
+            self.ramcloud.cmd( './start-ramcloud-%s.sh stop' % daemon )
+        self.ramcloud.terminate()
 
     def startZookeeper( self, initcfg=True ):
         "Start Zookeeper"
@@ -195,8 +223,10 @@
             cfg = self.zookeeperDir + '/conf/zoo.cfg'
             template = self.zookeeperDir + '/conf/zoo_sample.cfg'
             copyfile( template, cfg )
-        self.cmd( 'start-zk.sh restart' )
-        self.waitStart( 'Zookeeper', 'zookeeper' )
+        self.cmd( 'start-zk.sh stop' )
+        self.cmd( 'start-zk.sh start' )
+        pid = self.waitStart( 'Zookeeper', 'zookeeper' )
+        self.waitNetstat( pid )
         status = self.cmd( 'start-zk.sh status' )
         if 'Error' in status:
             raise Exception( 'Zookeeper startup failed: ' + status )
@@ -230,15 +260,13 @@
         """Set and return environment vars
            id: ONOS instance number
            propsFile: properties file name"""
-        # ONOS directories and files
-        logdir = self.logDir % id
         # cassdir = self.cassDir % id
         logback = self.logbackFile % id
         jmxport = self.jmxbase + id
-        self.cmd( 'mkdir -p', logdir ) # , cassdir
-        self.cmd( 'export ONOS_LOGDIR="%s"' % logdir )
+        logdir = self.logDir
+        self.cmd( 'export ONOS_LOGDIR=%s' % logdir )
+        self.cmd( 'export ONOS_LOGBASE=onos-%d.`hostname`' % id)
         self.cmd( 'export ZOO_LOG_DIR="%s"' % logdir )
-        # self.cmd( 'export CASS_DIR="%s"' % cassdir )
         self.cmd( 'export ONOS_LOGBACK="%s"' % logback )
         self.cmd( 'export JMX_PORT=%s' % jmxport )
         self.cmd( 'export JVM_OPTS="-D%s=%s"' % (
@@ -252,7 +280,7 @@
         self.stopONOS( id )
         propsFile = self.genProperties( id )
         self.setVars( id, propsFile )
-        self.cmdPrint( 'start-onos.sh startnokill' )
+        self.cmd( 'start-onos.sh startnokill' )
         # start-onos.sh waits for ONOS startup
         elapsed = time.time() - start
         info( '* ONOS %s started in %.2f seconds\n' % ( id, elapsed ) )
@@ -263,51 +291,49 @@
         pid = self.cmd( "jps -v | grep %s=%s | awk '{print $1}'" %
             ( self.proctag, id ) ).strip()
         if pid:
-            self.cmdPrint( 'kill', pid )
+            self.cmd( 'kill', pid )
 
     def start( self, *args ):
         "Start ONOS instances"
-        info( '* Starting Cassandra\n' )
-        self.startCassandra()
         info( '* Starting Zookeeper\n' )
         self.startZookeeper()
+        info( '* Starting Ramcloud\n' )
+        self.startRamcloud()
         for id in self.ids:
             info( '* Starting ONOS %s\n' % id )
             self.startONOS( id )
+        self.cmd( 'start-rest.sh start' )
+        # Initialize proxies for clist()
+        self.proxies = [ RemoteController( 'onos-%d' % id, port=(self.ofbase + id ) )
+            for id in range( 0, self.count ) ]
 
     def stop( self, *args ):
         "Stop ONOS instances"
+        self.cmd( 'start-rest.sh stop' )
         for id in self.ids:
             info( '* Stopping ONOS %s\n' % id )
             self.stopONOS( id )
         info( '* Stopping Zookeeper\n' )
         self.stopZookeeper()
-        info( '* Stopping Cassandra\n' )
-        self.stopCassandra()
+        info( '* Stopping Ramcloud\n' )
+        self.stopRamcloud()
+        for p in self.proxies:
+            p.stop()
+        p.proxies = []
 
     def clist( self ):
-        "Return list of controller specifiers (proto:ip:port)"
-        return [ 'tcp:127.0.0.1:%s' % ( self.ofbase + id )
-            for id in range( 0, self.count ) ]
+        "Return list of Controller proxies for this ONOS cluster"
+        return self.proxies
 
 
 class OVSSwitchONOS( OVSSwitch ):
     "OVS switch which connects to multiple controllers"
     def start( self, controllers ):
-        OVSSwitch.start( self, controllers )
         assert len( controllers ) == 1
         c0 = controllers[ 0 ]
         assert type( c0 ) == ONOS
-        clist = ','.join( c0.clist() )
-        self.cmd( 'ovs-vsctl set-controller', self, clist)
-        # Reconnect quickly to controllers (1s vs. 15s max_backoff)
-        for uuid in self.controllerUUIDs():
-            if uuid.count( '-' ) != 4:
-                # Doesn't look like a UUID
-                continue
-            uuid = uuid.strip()
-            self.cmd( 'ovs-vsctl set Controller', uuid,
-                      'max_backoff=1000' )
+        controllers = c0.clist()
+        OVSSwitch.start( self, controllers )
 
 
 def waitConnected( switches ):