Brian O'Connor | 195191b | 2014-10-22 01:09:36 -0700 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | |
| 3 | # TODO add onos-app-fwd to features |
| 4 | # TODO check if service is running... i think this might already be done by mn |
| 5 | |
| 6 | from mininet.node import Controller, OVSSwitch, CPULimitedHost, RemoteController |
| 7 | from mininet.net import Mininet |
| 8 | from mininet.cli import CLI |
| 9 | from mininet.topo import LinearTopo, Topo |
| 10 | from mininet.log import setLogLevel, info, warn |
| 11 | from mininet.util import quietRun, numCores |
| 12 | |
| 13 | from shutil import copyfile |
| 14 | from os import environ, path |
| 15 | from functools import partial |
| 16 | import time |
| 17 | from sys import argv |
| 18 | from time import sleep |
| 19 | |
| 20 | class ONOS( Controller ): |
| 21 | #def __init__( self, name, command='/opt/onos/bin/onos-service', **kwargs ): |
| 22 | # Controller.__init__( self, name, command=command, inNamespace=True, **kwargs ) |
| 23 | #def __init__( self, name, inNamespace=False, command='controller', |
| 24 | # cargs='-v ptcp:%d', cdir=None, ip="127.0.0.1", |
| 25 | # port=6633, protocol='tcp', **params ): |
| 26 | #self.command = command |
| 27 | #self.cargs = cargs |
| 28 | #self.cdir = cdir |
| 29 | #self.ip = ip |
| 30 | #self.port = port |
| 31 | #self.protocol = protocol |
| 32 | #Node.__init__( self, name, inNamespace=inNamespace, |
| 33 | # ip=ip, **params ) |
| 34 | #self.checkListening() |
| 35 | |
| 36 | ONOS_DIR = '/opt/onos/' |
| 37 | KARAF_DIR = ONOS_DIR + 'apache-karaf-3.0.1/' |
| 38 | reactive = True |
| 39 | |
| 40 | def start( self ): |
| 41 | # switch to the non-root user because karaf gets upset otherwise |
| 42 | # TODO we should look into why.... |
| 43 | self.sendCmd( 'sudo su - %s' % self.findUser() ) |
| 44 | self.waiting = False |
| 45 | |
| 46 | if self.inNamespace: |
| 47 | self.cmd( self.KARAF_DIR + 'bin/instance create %s' % self.name ) |
| 48 | src = self.KARAF_DIR + 'etc/org.apache.karaf.features.cfg' |
| 49 | dst = self.KARAF_DIR + 'instances/%s/etc/org.apache.karaf.features.cfg' % self.name |
| 50 | self.cmd( 'cp %s %s' % (src, dst) ) |
| 51 | self.updateProperties( dst ) |
| 52 | self.cmd( self.KARAF_DIR + 'bin/instance start %s' % self.name ) |
| 53 | else: |
| 54 | # we are running in the root namespace, so let's use the root instance |
| 55 | self.cmd( 'rm -rf '+ self.KARAF_DIR + 'data/' ) |
| 56 | filename = self.KARAF_DIR + 'etc/org.apache.karaf.features.cfg' |
| 57 | self.updateProperties( filename ) |
| 58 | self.cmd( self.KARAF_DIR + 'bin/start' ) |
| 59 | |
| 60 | #TODO we should wait for startup... |
| 61 | |
| 62 | def stop( self ): |
| 63 | if self.inNamespace: |
| 64 | self.cmd( '/opt/onos/apache-karaf-3.0.1/bin/instance stop %s' % self.name ) |
| 65 | self.cmd( '/opt/onos/apache-karaf-3.0.1/bin/instance destroy %s' % self.name ) |
| 66 | else: |
| 67 | self.cmd( self.ONOS_DIR + 'apache-karaf-3.0.1/bin/stop' ) |
| 68 | self.terminate() |
| 69 | |
| 70 | def updateProperties( self, filename ): |
| 71 | with open( filename, 'r+' ) as f: |
| 72 | lines = f.readlines() |
| 73 | f.seek(0) |
| 74 | f.truncate() |
| 75 | for line in lines: |
| 76 | #print '?', line, |
| 77 | if 'featuresBoot=' in line: |
| 78 | line = line.rstrip() |
| 79 | #print ord(line[-1]), ord(line[-2]), ord(line[-3]) |
| 80 | if self.reactive: |
| 81 | line += ',onos-app-fwd' |
| 82 | line += '\n' |
| 83 | #print '!', line, |
| 84 | f.write( line ) |
| 85 | |
| 86 | @classmethod |
| 87 | def isAvailable( self ): |
| 88 | return quietRun( 'ls /opt/onos' ) |
| 89 | |
| 90 | @staticmethod |
| 91 | def findUser(): |
| 92 | "Try to return logged-in (usually non-root) user" |
| 93 | try: |
| 94 | # If we're running sudo |
| 95 | return os.environ[ 'SUDO_USER' ] |
| 96 | except: |
| 97 | try: |
| 98 | # Logged-in user (if we have a tty) |
| 99 | return quietRun( 'who am i' ).split()[ 0 ] |
| 100 | except: |
| 101 | # Give up and return effective user |
| 102 | return quietRun( 'whoami' ) |
| 103 | |
| 104 | |
| 105 | class ControlNetwork( Topo ): |
| 106 | "Control Network Topology" |
| 107 | def __init__( self, n, dataController=ONOS, **kwargs ): |
| 108 | """n: number of data network controller nodes |
| 109 | dataController: class for data network controllers""" |
| 110 | Topo.__init__( self, **kwargs ) |
| 111 | # Connect everything to a single switch |
| 112 | cs0 = self.addSwitch( 'cs0' ) |
| 113 | # Add hosts which will serve as data network controllers |
| 114 | for i in range( 0, n ): |
| 115 | c = self.addHost( 'c%s' % i, cls=dataController, |
| 116 | inNamespace=True ) |
| 117 | self.addLink( c, cs0 ) |
| 118 | # Connect switch to root namespace so that data network |
| 119 | # switches will be able to talk to us |
| 120 | root = self.addHost( 'root', inNamespace=False ) |
| 121 | self.addLink( root, cs0 ) |
| 122 | |
| 123 | class ONOSCluster( Controller ): |
| 124 | # TODO |
| 125 | n = 4 |
| 126 | |
| 127 | def start( self ): |
| 128 | ctopo = ControlNetwork( n=self.n, dataController=ONOS ) |
| 129 | self.cnet = Mininet( topo=ctopo, ipBase='192.168.123.0/24', controller=None ) |
| 130 | self.cnet.addController( 'cc0', controller=Controller ) |
| 131 | self.cnet.start() |
| 132 | |
| 133 | self.ctrls = [] |
| 134 | for host in self.cnet.hosts: |
| 135 | if isinstance( host, Controller ): |
| 136 | self.ctrls.append( host ) |
| 137 | host.start() |
| 138 | |
| 139 | def stop( self ): |
| 140 | self.cnet.stop() |
| 141 | |
| 142 | def clist( self ): |
| 143 | "Return list of Controller proxies for this ONOS cluster" |
| 144 | print 'controllers:', self.ctrls |
| 145 | return self.ctrls |
| 146 | |
| 147 | class OVSSwitchONOS( OVSSwitch ): |
| 148 | "OVS switch which connects to multiple controllers" |
| 149 | def start( self, controllers ): |
| 150 | assert len( controllers ) == 1 |
| 151 | c0 = controllers[ 0 ] |
| 152 | assert type( c0 ) == ONOSCluster |
| 153 | controllers = c0.clist() |
| 154 | OVSSwitch.start( self, controllers ) |
| 155 | |
| 156 | controllers = { 'onos': ONOS } |
| 157 | switches = { 'ovso': OVSSwitchONOS } |
| 158 | |
| 159 | if __name__ == '__main__': |
| 160 | # Simple test for ONOS() controller class |
| 161 | setLogLevel( 'info' ) |
| 162 | size = 2 if len( argv ) != 2 else int( argv[ 1 ] ) |
| 163 | net = Mininet( topo=LinearTopo( size ), |
| 164 | controller=partial( ONOSCluster, n=4 ), |
| 165 | switch=OVSSwitchONOS ) |
| 166 | net.start() |
| 167 | #waitConnected( net.switches ) |
| 168 | CLI( net ) |
| 169 | net.stop() |