blob: 4283ff6c12e5d051047a8a855594d618ed0471d9 [file] [log] [blame]
You Wangdb927a52016-02-26 11:03:28 -08001"""
2This file contains classes for CHOTestMonkey that are related to application event
3Author: you@onlab.us
4"""
5from tests.CHOTestMonkey.dependencies.events.Event import EventType, EventStates, Event
6from tests.CHOTestMonkey.dependencies.elements.ONOSElement import HostIntent, PointIntent
7
8class IntentEvent( Event ):
9 def __init__( self ):
10 Event.__init__( self )
11 # The index of the ONOS CLI that is going to run the command
12 self.CLIIndex = 0
13
You Wang7a27f3a2016-07-05 10:12:27 -070014 def getRandomCorrespondent( self, hostA, connected=True ):
15 import random
16 if connected:
17 candidates = hostA.correspondents
18 else:
19 candidates = [ host for host in main.hosts if host not in hostA.correspondents and host != hostA ]
20 if len( candidates ) == 0:
21 return None
22 hostB = random.sample( candidates, 1 )[0]
23 return hostB
24
25 def getRandomHostPair( self, connected=True ):
26 import random
27 candidateDict = {}
28 with main.variableLock:
29 for host in main.hosts:
30 correspondent = self.getRandomCorrespondent( host, connected=connected )
31 if correspondent != None:
32 candidateDict[ host ] = correspondent
33 if candidateDict == {}:
34 return None
35 hostA = random.sample( candidateDict.keys(), 1 )[0]
36 hostB = candidateDict[ hostA ]
37 return [ hostA, hostB ]
38
39 def getIntentsByType( self, intentType ):
40 intents = []
41 with main.variableLock:
42 for intent in main.intents:
43 if intent.type == intentType:
44 intents.append( intent )
45 return intents
46
47 def getRandomIntentByType( self, intentType ):
48 import random
49 intents = self.getIntentsByType( intentType )
50 if len( intents ) == 0:
51 return None
52 intent = random.sample( intents, 1 )[ 0 ]
53 return intent
54
You Wangdb927a52016-02-26 11:03:28 -080055class HostIntentEvent( IntentEvent ):
56 def __init__( self ):
57 IntentEvent.__init__( self )
58 self.hostA = None
59 self.hostB = None
60
61 def startHostIntentEvent( self ):
62 return EventStates().PASS
63
64 def startEvent( self, args ):
65 with self.eventLock:
You Wang52163202016-07-14 16:37:15 -070066 #main.log.info( "%s - starting event" % ( self.typeString ) )
You Wangdb927a52016-02-26 11:03:28 -080067 if self.typeIndex == EventType().APP_INTENT_HOST_ADD or self.typeIndex == EventType().APP_INTENT_HOST_DEL:
68 if len( args ) < 3:
69 main.log.warn( "%s - Not enough arguments: %s" % ( self.typeString, args ) )
70 return EventStates().ABORT
71 elif len( args ) > 3:
72 main.log.warn( "%s - Too many arguments: %s" % ( self.typeString, args ) )
73 return EventStates().ABORT
You Wang59dfeb62016-07-14 09:47:33 -070074 try:
75 if args[ 0 ] == 'random' or args[ 1 ] == 'random':
76 if self.typeIndex == EventType().APP_INTENT_HOST_ADD:
77 hostPairRandom = self.getRandomHostPair( connected=False )
78 if hostPairRandom == None:
79 main.log.warn( "All host pairs are connected, aborting event" )
80 return EventStates().ABORT
81 self.hostA = hostPairRandom[ 0 ]
82 self.hostB = hostPairRandom[ 1 ]
83 elif self.typeIndex == EventType().APP_INTENT_HOST_DEL:
84 intent = self.getRandomIntentByType( 'INTENT_HOST' )
85 if intent == None:
86 main.log.warn( "No host intent for deletion, aborting event" )
87 return EventStates().ABORT
88 self.hostA = intent.hostA
89 self.hostB = intent.hostB
90 elif args[ 0 ] == args[ 1 ]:
91 main.log.warn( "%s - invalid argument: %s, %s" % ( self.typeString, args[ 0 ], args[ 1 ] ) )
You Wangdb927a52016-02-26 11:03:28 -080092 return EventStates().ABORT
You Wang59dfeb62016-07-14 09:47:33 -070093 else:
94 for host in main.hosts:
95 if host.name == args[ 0 ]:
96 self.hostA = host
97 elif host.name == args[ 1 ]:
98 self.hostB = host
99 if self.hostA != None and self.hostB != None:
100 break
101 if self.hostA == None:
102 main.log.warn( "Host %s does not exist: " % ( args[ 0 ] ) )
103 return EventStates().ABORT
104 if self.hostB == None:
105 main.log.warn( "Host %s does not exist: " % ( args[ 1 ] ) )
106 return EventStates().ABORT
107 index = int( args[ 2 ] )
108 if index < 1 or index > int( main.numCtrls ):
109 main.log.warn( "%s - invalid argument: %s" % ( self.typeString, index ) )
You Wangdb927a52016-02-26 11:03:28 -0800110 return EventStates().ABORT
You Wang59dfeb62016-07-14 09:47:33 -0700111 if not main.controllers[ index - 1 ].isUp():
112 main.log.warn( self.typeString + " - invalid argument: onos %s is down" % ( controller.index ) )
113 return EventStates().ABORT
114 self.CLIIndex = index
115 return self.startHostIntentEvent()
116 except Exception:
117 main.log.warn( "Caught exception, aborting event" )
You Wang7a27f3a2016-07-05 10:12:27 -0700118 return EventStates().ABORT
You Wangdb927a52016-02-26 11:03:28 -0800119
120class AddHostIntent( HostIntentEvent ):
121 """
122 Add a host-to-host intent (bidirectional)
123 """
124 def __init__( self ):
125 HostIntentEvent.__init__( self )
126 self.typeString = main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeString' ]
127 self.typeIndex= int( main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeIndex' ] )
128
129 def startHostIntentEvent( self ):
You Wang7a27f3a2016-07-05 10:12:27 -0700130 try:
131 assert self.hostA != None and self.hostB != None
132 # Check whether there already exists some intent for the host pair
133 # For now we should avoid installing overlapping intents
134 for intent in main.intents:
135 if not intent.type == 'INTENT_HOST':
136 continue
137 if intent.hostA == self.hostA and intent.hostB == self.hostB or\
138 intent.hostB == self.hostA and intent.hostA == self.hostB:
139 main.log.warn( self.typeString + " - find an exiting intent for the host pair, abort installation" )
140 return EventStates().ABORT
You Wang52163202016-07-14 16:37:15 -0700141 main.log.info( "Event recorded: {} {} {} {} {}".format( self.typeIndex, self.typeString, self.hostA.name, self.hostB.name, self.CLIIndex ) )
You Wang7a27f3a2016-07-05 10:12:27 -0700142 controller = main.controllers[ self.CLIIndex - 1 ]
143 with controller.CLILock:
144 id = controller.CLI.addHostIntent( self.hostA.id, self.hostB.id )
145 if id == None:
146 main.log.warn( self.typeString + " - add host intent failed" )
147 return EventStates().FAIL
148 with main.variableLock:
149 newHostIntent = HostIntent( id, self.hostA, self.hostB )
150 if self.hostA.isDown() or self.hostA.isRemoved() or self.hostB.isDown() or self.hostB.isRemoved():
151 newHostIntent.setFailed()
You Wang56577c82016-07-12 10:49:23 -0700152 else:
153 newHostIntent.setInstalled()
You Wang7a27f3a2016-07-05 10:12:27 -0700154 main.intents.append( newHostIntent )
You Wang7a27f3a2016-07-05 10:12:27 -0700155 return EventStates().PASS
156 except Exception:
157 main.log.warn( "Caught exception, aborting event" )
158 return EventStates().ABORT
You Wangdb927a52016-02-26 11:03:28 -0800159
160class DelHostIntent( HostIntentEvent ):
161 """
162 Delete a host-to-host intent (bidirectional)
163 """
164 def __init__( self ):
165 HostIntentEvent.__init__( self )
166 self.typeString = main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeString' ]
167 self.typeIndex= int( main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeIndex' ] )
168
169 def startHostIntentEvent( self ):
You Wang7a27f3a2016-07-05 10:12:27 -0700170 try:
171 assert self.hostA != None and self.hostB != None
172 targetIntent = None
173 for intent in main.intents:
174 if not intent.type == 'INTENT_HOST':
175 continue
176 if intent.hostA == self.hostA and intent.hostB == self.hostB or\
177 intent.hostB == self.hostA and intent.hostA == self.hostB:
178 targetIntent = intent
179 break
180 if targetIntent == None:
181 main.log.warn( self.typeString + " - intent does not exist" )
182 return EventStates().FAIL
You Wang52163202016-07-14 16:37:15 -0700183 main.log.info( "Event recorded: {} {} {} {} {}".format( self.typeIndex, self.typeString, self.hostA.name, self.hostB.name, self.CLIIndex ) )
You Wang7a27f3a2016-07-05 10:12:27 -0700184 controller = main.controllers[ self.CLIIndex - 1 ]
185 with controller.CLILock:
186 result = controller.CLI.removeIntent( targetIntent.id, purge=True )
187 if result == None or result == main.FALSE:
188 main.log.warn( self.typeString + " - delete host intent failed" )
189 return EventStates().FAIL
190 with main.variableLock:
You Wang56577c82016-07-12 10:49:23 -0700191 targetIntent.setWithdrawn()
You Wang7a27f3a2016-07-05 10:12:27 -0700192 main.intents.remove( targetIntent )
You Wang7a27f3a2016-07-05 10:12:27 -0700193 return EventStates().PASS
194 except Exception:
195 main.log.warn( "Caught exception, aborting event" )
196 return EventStates().ABORT
You Wangdb927a52016-02-26 11:03:28 -0800197
198class PointIntentEvent( IntentEvent ):
199 def __init__( self ):
200 IntentEvent.__init__( self )
201 self.deviceA = None
202 self.deviceB = None
203
204 def startPointIntentEvent( self ):
205 return EventStates().PASS
206
207 def startEvent( self, args ):
208 with self.eventLock:
You Wang52163202016-07-14 16:37:15 -0700209 #main.log.info( "%s - starting event" % ( self.typeString ) )
You Wangdb927a52016-02-26 11:03:28 -0800210 if self.typeIndex == EventType().APP_INTENT_POINT_ADD or self.typeIndex == EventType().APP_INTENT_POINT_DEL:
211 if len( args ) < 3:
212 main.log.warn( "%s - Not enough arguments: %s" % ( self.typeString, args ) )
213 return EventStates().ABORT
You Wang7a27f3a2016-07-05 10:12:27 -0700214 elif len( args ) > 4:
You Wangdb927a52016-02-26 11:03:28 -0800215 main.log.warn( "%s - Too many arguments: %s" % ( self.typeString, args ) )
216 return EventStates().ABORT
You Wang59dfeb62016-07-14 09:47:33 -0700217 try:
218 if args[ 0 ] == 'random' or args[ 1 ] == 'random':
219 if self.typeIndex == EventType().APP_INTENT_POINT_ADD:
220 hostPairRandom = self.getRandomHostPair( connected=False )
221 if hostPairRandom == None:
222 main.log.warn( "All host pairs are connected, aborting event" )
223 return EventStates().ABORT
224 self.deviceA = hostPairRandom[ 0 ].device
225 self.deviceB = hostPairRandom[ 1 ].device
226 elif self.typeIndex == EventType().APP_INTENT_POINT_DEL:
227 intent = self.getRandomIntentByType( 'INTENT_POINT' )
228 if intent == None:
229 main.log.warn( "No point intent for deletion, aborting event" )
230 return EventStates().ABORT
231 self.deviceA = intent.deviceA
232 self.deviceB = intent.deviceB
233 elif args[ 0 ] == args[ 1 ]:
234 main.log.warn( "%s - invalid argument: %s" % ( self.typeString, args[ 0 ], args[ 1 ] ) )
You Wangdb927a52016-02-26 11:03:28 -0800235 return EventStates().ABORT
You Wang7a27f3a2016-07-05 10:12:27 -0700236 else:
You Wang59dfeb62016-07-14 09:47:33 -0700237 for device in main.devices:
238 if device.name == args[ 0 ]:
239 self.deviceA = device
240 elif device.name == args[ 1 ]:
241 self.deviceB = device
242 if self.deviceA != None and self.deviceB != None:
243 break
244 if self.deviceA == None:
245 main.log.warn( "Device %s does not exist: " % ( args[ 0 ] ) )
246 return EventStates().ABORT
247 if self.deviceB == None:
248 main.log.warn( "Device %s does not exist: " % ( args[ 1 ] ) )
249 return EventStates().ABORT
250 index = int( args[ 2 ] )
251 if index < 1 or index > int( main.numCtrls ):
252 main.log.warn( "%s - invalid argument: %s" % ( self.typeString, index ) )
253 return EventStates().ABORT
254 if not main.controllers[ index - 1 ].isUp():
255 main.log.warn( self.typeString + " - invalid argument: onos %s is down" % ( controller.index ) )
256 return EventStates().ABORT
257 self.CLIIndex = index
258 if len( args ) == 4 and args[ 3 ] == 'bidirectional':
259 # Install point intents for both directions
260 resultA = self.startPointIntentEvent()
261 [ self.deviceA, self.deviceB ] = [ self.deviceB, self.deviceA ]
262 resultB = self.startPointIntentEvent()
263 if resultA == EventStates().PASS and resultB == EventStates().PASS:
264 return EventStates().PASS
265 else:
266 return EventStates().FAIL
267 else:
268 return self.startPointIntentEvent()
269 except Exception:
270 main.log.warn( "Caught exception, aborting event" )
271 return EventStates().ABORT
You Wangdb927a52016-02-26 11:03:28 -0800272
273class AddPointIntent( PointIntentEvent ):
274 """
275 Add a point-to-point intent
276 """
277 def __init__( self ):
278 PointIntentEvent.__init__( self )
279 self.typeString = main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeString' ]
280 self.typeIndex= int( main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeIndex' ] )
281
282 def startPointIntentEvent( self ):
You Wang7a27f3a2016-07-05 10:12:27 -0700283 try:
284 assert self.deviceA != None and self.deviceB != None
285 controller = main.controllers[ self.CLIIndex - 1 ]
You Wang59dfeb62016-07-14 09:47:33 -0700286 # TODO: support multiple hosts under one device
You Wang7a27f3a2016-07-05 10:12:27 -0700287 # Check whether there already exists some intent for the device pair
288 # For now we should avoid installing overlapping intents
289 for intent in main.intents:
290 if not intent.type == 'INTENT_POINT':
291 continue
292 if intent.deviceA == self.deviceA and intent.deviceB == self.deviceB:
293 main.log.warn( self.typeString + " - find an exiting intent for the device pair, abort installation" )
294 return EventStates().ABORT
You Wang52163202016-07-14 16:37:15 -0700295 main.log.info( "Event recorded: {} {} {} {} {}".format( self.typeIndex, self.typeString, self.deviceA.name, self.deviceB.name, self.CLIIndex ) )
You Wang7a27f3a2016-07-05 10:12:27 -0700296 controller = main.controllers[ self.CLIIndex - 1 ]
297 with controller.CLILock:
You Wang7a27f3a2016-07-05 10:12:27 -0700298 srcMAC = ""
299 dstMAC = ""
300 if len( self.deviceA.hosts ) > 0:
301 srcMAC = self.deviceA.hosts[ 0 ].mac
302 if len( self.deviceB.hosts ) > 0:
303 dstMAC = self.deviceB.hosts[ 0 ].mac
You Wang59dfeb62016-07-14 09:47:33 -0700304 id = controller.CLI.addPointIntent( self.deviceA.dpid, self.deviceB.dpid, 1, 1, '', srcMAC, dstMAC )
You Wang7a27f3a2016-07-05 10:12:27 -0700305 if id == None:
306 main.log.warn( self.typeString + " - add point intent failed" )
307 return EventStates().FAIL
308 with main.variableLock:
309 newPointIntent = PointIntent( id, self.deviceA, self.deviceB )
310 if self.deviceA.isDown() or self.deviceB.isDown() or self.deviceA.isRemoved() or self.deviceB.isRemoved():
311 newPointIntent.setFailed()
You Wang56577c82016-07-12 10:49:23 -0700312 else:
313 newPointIntent.setInstalled()
You Wang7a27f3a2016-07-05 10:12:27 -0700314 main.intents.append( newPointIntent )
You Wang7a27f3a2016-07-05 10:12:27 -0700315 return EventStates().PASS
316 except Exception:
317 main.log.warn( "Caught exception, aborting event" )
318 return EventStates().ABORT
You Wangdb927a52016-02-26 11:03:28 -0800319
320class DelPointIntent( PointIntentEvent ):
321 """
322 Delete a point-to-point intent
323 """
324 def __init__( self ):
325 PointIntentEvent.__init__( self )
326 self.typeString = main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeString' ]
327 self.typeIndex= int( main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeIndex' ] )
328
329 def startPointIntentEvent( self ):
You Wang7a27f3a2016-07-05 10:12:27 -0700330 try:
331 assert self.deviceA != None and self.deviceB != None
332 targetIntent = None
333 for intent in main.intents:
334 if not intent.type == 'INTENT_POINT':
335 continue
336 if intent.deviceA == self.deviceA and intent.deviceB == self.deviceB:
337 targetIntent = intent
338 break
339 if targetIntent == None:
340 main.log.warn( self.typeString + " - intent does not exist" )
341 return EventStates().FAIL
You Wang52163202016-07-14 16:37:15 -0700342 main.log.info( "Event recorded: {} {} {} {} {}".format( self.typeIndex, self.typeString, self.deviceA.name, self.deviceB.name, self.CLIIndex ) )
You Wang7a27f3a2016-07-05 10:12:27 -0700343 controller = main.controllers[ self.CLIIndex - 1 ]
344 with controller.CLILock:
345 result = controller.CLI.removeIntent( targetIntent.id, purge=True )
346 if result == None or result == main.FALSE:
347 main.log.warn( self.typeString + " - delete point intent failed" )
348 return EventStates().FAIL
349 with main.variableLock:
You Wang56577c82016-07-12 10:49:23 -0700350 targetIntent.setWithdrawn()
You Wang7a27f3a2016-07-05 10:12:27 -0700351 main.intents.remove( targetIntent )
You Wang7a27f3a2016-07-05 10:12:27 -0700352 return EventStates().PASS
353 except Exception:
354 main.log.warn( "Caught exception, aborting event" )
355 return EventStates().ABORT