blob: 80a80059a01c8b0c2a32f58ca321d9685897c708 [file] [log] [blame]
Brian O'Connor195191b2014-10-22 01:09:36 -07001#!/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
6from mininet.node import Controller, OVSSwitch, CPULimitedHost, RemoteController
7from mininet.net import Mininet
8from mininet.cli import CLI
9from mininet.topo import LinearTopo, Topo
10from mininet.log import setLogLevel, info, warn
11from mininet.util import quietRun, numCores
12
13from shutil import copyfile
14from os import environ, path
15from functools import partial
16import time
17from sys import argv
18from time import sleep
Brian O'Connor67eb3802014-10-22 19:55:38 -070019from sets import Set
Brian O'Connor195191b2014-10-22 01:09:36 -070020
21class ONOS( Controller ):
Brian O'Connor67eb3802014-10-22 19:55:38 -070022 "TODO"
23
24 onosDir = '/opt/onos/'
25
26 def __init__( self, name, onosDir=onosDir,
27 reactive=True, features=[ 'onos-app-tvue' ],
28 **kwargs ):
29 '''TODO'''
30
31 Controller.__init__( self, name, **kwargs )
32 # the following have been done for us:
33 #self.ip = ip ('127.0.0.1')
34 #self.port = port (6633)
35 #self.protocol = protocol ('tcp')
36 #self.checkListening()
37
38 self.onosDir = onosDir
Pavlin Radoslavovc5227052014-11-04 10:55:19 -080039 self.karafDir = onosDir + 'apache-karaf-3.0.2/'
Brian O'Connor67eb3802014-10-22 19:55:38 -070040 self.instanceDir = self.karafDir
41
42 # add default modules
43 # TODO: consider an ordered set
44 self.features = Set([ 'webconsole',
45 'onos-api',
46 'onos-cli',
47 'onos-openflow' ])
48 self.features.update( features )
49 # add reactive forwarding modules
50 if reactive:
51 self.features.update( ['onos-app-fwd',
52 'onos-app-proxyarp',
53 'onos-app-mobility' ] )
54 # add the distributed core if we are in a namespace with no trivial core
55 if self.inNamespace and 'onos-core-trivial' not in self.features:
56 self.features.add( 'onos-core' )
57 # if there is no core, add the trivial one
58 if 'onos-core' not in self.features:
59 self.features.add( 'onos-core-trivial' )
60 print self.features
Brian O'Connor195191b2014-10-22 01:09:36 -070061
62 def start( self ):
Brian O'Connor195191b2014-10-22 01:09:36 -070063 if self.inNamespace:
Brian O'Connor67eb3802014-10-22 19:55:38 -070064 instanceOpts = ( '-furl mvn:org.onlab.onos/onos-features/1.0.0-SNAPSHOT/xml/features '
65 '-s 8101' )
66 self.userCmd( self.karafDir + 'bin/instance create %s %s' % ( instanceOpts, self.name ) )
67 self.instanceDir = self.karafDir + 'instances/%s/' % self.name
Brian O'Connor195191b2014-10-22 01:09:36 -070068 else:
69 # we are running in the root namespace, so let's use the root instance
Brian O'Connor67eb3802014-10-22 19:55:38 -070070 # clean up the data directory
71 #self.userCmd( 'rm -rf '+ self.karafDir + 'data/' )
72 pass
Brian O'Connor195191b2014-10-22 01:09:36 -070073
Brian O'Connor67eb3802014-10-22 19:55:38 -070074 self.userCmd( 'rm -rf '+ self.instanceDir + 'data/' )
75
76 # Update etc/org.apache.karaf.features.cfg
77 self.updateFeatures()
78
79 # TODO 2. Update etc/hazelcast.xml : interface lines
80 #cp etc/hazelcast.xml instances/c1/etc/
81 self.updateHazelcast()
82
83 # TODO 3. Update etc/system.properties : onos.ip
84 # TODO 4. Update config/cluster.json : with all nodes
85
86 # start onos
87 self.userCmd( self.instanceDir + 'bin/start' )
Brian O'Connor195191b2014-10-22 01:09:36 -070088 #TODO we should wait for startup...
89
90 def stop( self ):
Brian O'Connor67eb3802014-10-22 19:55:38 -070091 self.userCmd( self.instanceDir + 'bin/stop' )
92 #if self.inNamespace:
93 # self.userCmd( self.karafDir + 'bin/instance destroy %s' % self.name )
Brian O'Connor195191b2014-10-22 01:09:36 -070094 self.terminate()
95
Brian O'Connor67eb3802014-10-22 19:55:38 -070096 def updateHazelcast( self ):
97 readfile = self.karafDir + 'etc/hazelcast.xml'
98 writefile = self.instanceDir + 'etc/hazelcast.xml'
99 with open( readfile, 'r' ) as r:
100 with open( writefile, 'w' ) as w:
101 for line in r.readlines():
102 if '<interface>' in line:
103 line = '<interface>' + '192.168.123.*' + '</interface>\n'
104 w.write( line )
105
106 def updateFeatures( self ):
107 filename = self.instanceDir + 'etc/org.apache.karaf.features.cfg'
Brian O'Connor195191b2014-10-22 01:09:36 -0700108 with open( filename, 'r+' ) as f:
109 lines = f.readlines()
110 f.seek(0)
111 f.truncate()
112 for line in lines:
113 #print '?', line,
114 if 'featuresBoot=' in line:
Brian O'Connor67eb3802014-10-22 19:55:38 -0700115 # parse the features from the line
116 features = line.rstrip().split('=')[1].split(',')
117 # add the features to our features set
118 self.features.update( features )
119 # generate the new features line
120 line = 'featuresBoot=' + ','.join( self.features ) + '\n'
Brian O'Connor195191b2014-10-22 01:09:36 -0700121 #print '!', line,
122 f.write( line )
123
Brian O'Connor67eb3802014-10-22 19:55:38 -0700124
Brian O'Connor195191b2014-10-22 01:09:36 -0700125 @classmethod
126 def isAvailable( self ):
Brian O'Connor67eb3802014-10-22 19:55:38 -0700127 return quietRun( 'ls %s' % self.onosDir )
128
129 def userCmd( self, cmd ):
130 # switch to the non-root user because karaf gets upset otherwise
131 # because the .m2repo is not stored with root
132 cmd = 'sudo -u %s %s' % ( self.findUser(), cmd )
133 return self.cmd( cmd )
Brian O'Connor195191b2014-10-22 01:09:36 -0700134
135 @staticmethod
136 def findUser():
137 "Try to return logged-in (usually non-root) user"
138 try:
139 # If we're running sudo
140 return os.environ[ 'SUDO_USER' ]
141 except:
142 try:
143 # Logged-in user (if we have a tty)
144 return quietRun( 'who am i' ).split()[ 0 ]
145 except:
146 # Give up and return effective user
147 return quietRun( 'whoami' )
148
149
150class ControlNetwork( Topo ):
151 "Control Network Topology"
152 def __init__( self, n, dataController=ONOS, **kwargs ):
153 """n: number of data network controller nodes
154 dataController: class for data network controllers"""
155 Topo.__init__( self, **kwargs )
156 # Connect everything to a single switch
157 cs0 = self.addSwitch( 'cs0' )
158 # Add hosts which will serve as data network controllers
Brian O'Connor67eb3802014-10-22 19:55:38 -0700159 for i in range( 1, n+1 ):
Brian O'Connor195191b2014-10-22 01:09:36 -0700160 c = self.addHost( 'c%s' % i, cls=dataController,
161 inNamespace=True )
162 self.addLink( c, cs0 )
163 # Connect switch to root namespace so that data network
164 # switches will be able to talk to us
165 root = self.addHost( 'root', inNamespace=False )
166 self.addLink( root, cs0 )
167
168class ONOSCluster( Controller ):
169 # TODO
Brian O'Connor67eb3802014-10-22 19:55:38 -0700170 n = 3
Brian O'Connor195191b2014-10-22 01:09:36 -0700171
172 def start( self ):
173 ctopo = ControlNetwork( n=self.n, dataController=ONOS )
174 self.cnet = Mininet( topo=ctopo, ipBase='192.168.123.0/24', controller=None )
175 self.cnet.addController( 'cc0', controller=Controller )
176 self.cnet.start()
177
178 self.ctrls = []
179 for host in self.cnet.hosts:
180 if isinstance( host, Controller ):
181 self.ctrls.append( host )
182 host.start()
183
184 def stop( self ):
Brian O'Connor67eb3802014-10-22 19:55:38 -0700185 for host in self.cnet.hosts:
186 if isinstance( host, Controller ):
187 host.stop()
Brian O'Connor195191b2014-10-22 01:09:36 -0700188 self.cnet.stop()
189
190 def clist( self ):
191 "Return list of Controller proxies for this ONOS cluster"
192 print 'controllers:', self.ctrls
193 return self.ctrls
194
195class OVSSwitchONOS( OVSSwitch ):
196 "OVS switch which connects to multiple controllers"
197 def start( self, controllers ):
198 assert len( controllers ) == 1
199 c0 = controllers[ 0 ]
200 assert type( c0 ) == ONOSCluster
201 controllers = c0.clist()
202 OVSSwitch.start( self, controllers )
203
204controllers = { 'onos': ONOS }
205switches = { 'ovso': OVSSwitchONOS }
206
207if __name__ == '__main__':
208 # Simple test for ONOS() controller class
Brian O'Connor67eb3802014-10-22 19:55:38 -0700209 setLogLevel( 'info' ) #TODO info
Brian O'Connor195191b2014-10-22 01:09:36 -0700210 size = 2 if len( argv ) != 2 else int( argv[ 1 ] )
211 net = Mininet( topo=LinearTopo( size ),
Brian O'Connor67eb3802014-10-22 19:55:38 -0700212 #controller=ONOS,
213 controller=partial( ONOSCluster, n=3 ), #TODO
Brian O'Connor195191b2014-10-22 01:09:36 -0700214 switch=OVSSwitchONOS )
215 net.start()
216 #waitConnected( net.switches )
217 CLI( net )
218 net.stop()