blob: 8113b099d2d5ea6fb072ede34669a572d0fa35b9 [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:
66 main.log.info( "%s - starting event" % ( self.typeString ) )
67 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 Wang7a27f3a2016-07-05 10:12:27 -070074 if args[ 0 ] == 'random' or args[ 1 ] == 'random':
75 if self.typeIndex == EventType().APP_INTENT_HOST_ADD:
76 hostPairRandom = self.getRandomHostPair( connected=False )
77 if hostPairRandom == None:
78 main.log.warn( "All host pairs are connected, aborting event" )
79 return EventStates().ABORT
80 self.hostA = hostPairRandom[ 0 ]
81 self.hostB = hostPairRandom[ 1 ]
82 elif self.typeIndex == EventType().APP_INTENT_HOST_DEL:
83 intent = self.getRandomIntentByType( 'INTENT_HOST' )
84 if intent == None:
85 main.log.warn( "No host intent for deletion, aborting event" )
86 return EventStates().ABORT
87 self.hostA = intent.hostA
88 self.hostB = intent.hostB
89 elif args[ 0 ] == args[ 1 ]:
90 main.log.warn( "%s - invalid argument: %s, %s" % ( self.typeString, args[ 0 ], args[ 1 ] ) )
91 return EventStates().ABORT
You Wangdb927a52016-02-26 11:03:28 -080092 else:
You Wangdb927a52016-02-26 11:03:28 -080093 for host in main.hosts:
94 if host.name == args[ 0 ]:
95 self.hostA = host
96 elif host.name == args[ 1 ]:
97 self.hostB = host
98 if self.hostA != None and self.hostB != None:
99 break
100 if self.hostA == None:
101 main.log.warn( "Host %s does not exist: " % ( args[ 0 ] ) )
102 return EventStates().ABORT
103 if self.hostB == None:
104 main.log.warn( "Host %s does not exist: " % ( args[ 1 ] ) )
105 return EventStates().ABORT
You Wang7a27f3a2016-07-05 10:12:27 -0700106 index = int( args[ 2 ] )
107 if index < 1 or index > int( main.numCtrls ):
108 main.log.warn( "%s - invalid argument: %s" % ( self.typeString, index ) )
109 return EventStates().ABORT
110 if not main.controllers[ index - 1 ].isUp():
111 main.log.warn( self.typeString + " - invalid argument: onos %s is down" % ( controller.index ) )
112 return EventStates().ABORT
113 self.CLIIndex = index
114 return self.startHostIntentEvent()
You Wangdb927a52016-02-26 11:03:28 -0800115
116class AddHostIntent( HostIntentEvent ):
117 """
118 Add a host-to-host intent (bidirectional)
119 """
120 def __init__( self ):
121 HostIntentEvent.__init__( self )
122 self.typeString = main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeString' ]
123 self.typeIndex= int( main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeIndex' ] )
124
125 def startHostIntentEvent( self ):
You Wang7a27f3a2016-07-05 10:12:27 -0700126 try:
127 assert self.hostA != None and self.hostB != None
128 # Check whether there already exists some intent for the host pair
129 # For now we should avoid installing overlapping intents
130 for intent in main.intents:
131 if not intent.type == 'INTENT_HOST':
132 continue
133 if intent.hostA == self.hostA and intent.hostB == self.hostB or\
134 intent.hostB == self.hostA and intent.hostA == self.hostB:
135 main.log.warn( self.typeString + " - find an exiting intent for the host pair, abort installation" )
136 return EventStates().ABORT
137 controller = main.controllers[ self.CLIIndex - 1 ]
138 with controller.CLILock:
139 id = controller.CLI.addHostIntent( self.hostA.id, self.hostB.id )
140 if id == None:
141 main.log.warn( self.typeString + " - add host intent failed" )
142 return EventStates().FAIL
143 with main.variableLock:
144 newHostIntent = HostIntent( id, self.hostA, self.hostB )
145 if self.hostA.isDown() or self.hostA.isRemoved() or self.hostB.isDown() or self.hostB.isRemoved():
146 newHostIntent.setFailed()
147 main.intents.append( newHostIntent )
148 # Update host connectivity status
149 # TODO: should we check whether hostA and hostB are already correspondents?
150 self.hostB.correspondents.append( self.hostA )
151 self.hostA.correspondents.append( self.hostB )
152 return EventStates().PASS
153 except Exception:
154 main.log.warn( "Caught exception, aborting event" )
155 return EventStates().ABORT
You Wangdb927a52016-02-26 11:03:28 -0800156
157class DelHostIntent( HostIntentEvent ):
158 """
159 Delete a host-to-host intent (bidirectional)
160 """
161 def __init__( self ):
162 HostIntentEvent.__init__( self )
163 self.typeString = main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeString' ]
164 self.typeIndex= int( main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeIndex' ] )
165
166 def startHostIntentEvent( self ):
You Wang7a27f3a2016-07-05 10:12:27 -0700167 try:
168 assert self.hostA != None and self.hostB != None
169 targetIntent = None
170 for intent in main.intents:
171 if not intent.type == 'INTENT_HOST':
172 continue
173 if intent.hostA == self.hostA and intent.hostB == self.hostB or\
174 intent.hostB == self.hostA and intent.hostA == self.hostB:
175 targetIntent = intent
176 break
177 if targetIntent == None:
178 main.log.warn( self.typeString + " - intent does not exist" )
179 return EventStates().FAIL
180 controller = main.controllers[ self.CLIIndex - 1 ]
181 with controller.CLILock:
182 result = controller.CLI.removeIntent( targetIntent.id, purge=True )
183 if result == None or result == main.FALSE:
184 main.log.warn( self.typeString + " - delete host intent failed" )
185 return EventStates().FAIL
186 with main.variableLock:
187 main.intents.remove( targetIntent )
188 # Update host connectivity status
189 self.hostB.correspondents.remove( self.hostA )
190 self.hostA.correspondents.remove( self.hostB )
191 return EventStates().PASS
192 except Exception:
193 main.log.warn( "Caught exception, aborting event" )
194 return EventStates().ABORT
You Wangdb927a52016-02-26 11:03:28 -0800195
196class PointIntentEvent( IntentEvent ):
197 def __init__( self ):
198 IntentEvent.__init__( self )
199 self.deviceA = None
200 self.deviceB = None
201
202 def startPointIntentEvent( self ):
203 return EventStates().PASS
204
205 def startEvent( self, args ):
206 with self.eventLock:
207 main.log.info( "%s - starting event" % ( self.typeString ) )
208 if self.typeIndex == EventType().APP_INTENT_POINT_ADD or self.typeIndex == EventType().APP_INTENT_POINT_DEL:
209 if len( args ) < 3:
210 main.log.warn( "%s - Not enough arguments: %s" % ( self.typeString, args ) )
211 return EventStates().ABORT
You Wang7a27f3a2016-07-05 10:12:27 -0700212 elif len( args ) > 4:
You Wangdb927a52016-02-26 11:03:28 -0800213 main.log.warn( "%s - Too many arguments: %s" % ( self.typeString, args ) )
214 return EventStates().ABORT
You Wang7a27f3a2016-07-05 10:12:27 -0700215 if args[ 0 ] == 'random' or args[ 1 ] == 'random':
216 if self.typeIndex == EventType().APP_INTENT_POINT_ADD:
217 hostPairRandom = self.getRandomHostPair( connected=False )
218 if hostPairRandom == None:
219 main.log.warn( "All host pairs are connected, aborting event" )
220 return EventStates().ABORT
221 self.deviceA = hostPairRandom[ 0 ].device
222 self.deviceB = hostPairRandom[ 1 ].device
223 elif self.typeIndex == EventType().APP_INTENT_POINT_DEL:
224 intent = self.getRandomIntentByType( 'INTENT_POINT' )
225 if intent == None:
226 main.log.warn( "No point intent for deletion, aborting event" )
227 return EventStates().ABORT
228 self.deviceA = intent.deviceA
229 self.deviceB = intent.deviceB
230 elif args[ 0 ] == args[ 1 ]:
231 main.log.warn( "%s - invalid argument: %s" % ( self.typeString, args[ 0 ], args[ 1 ] ) )
232 return EventStates().ABORT
You Wangdb927a52016-02-26 11:03:28 -0800233 else:
234 for device in main.devices:
235 if device.name == args[ 0 ]:
236 self.deviceA = device
237 elif device.name == args[ 1 ]:
238 self.deviceB = device
239 if self.deviceA != None and self.deviceB != None:
240 break
241 if self.deviceA == None:
242 main.log.warn( "Device %s does not exist: " % ( args[ 0 ] ) )
243 return EventStates().ABORT
244 if self.deviceB == None:
245 main.log.warn( "Device %s does not exist: " % ( args[ 1 ] ) )
246 return EventStates().ABORT
You Wang7a27f3a2016-07-05 10:12:27 -0700247 index = int( args[ 2 ] )
248 if index < 1 or index > int( main.numCtrls ):
249 main.log.warn( "%s - invalid argument: %s" % ( self.typeString, index ) )
250 return EventStates().ABORT
251 if not main.controllers[ index - 1 ].isUp():
252 main.log.warn( self.typeString + " - invalid argument: onos %s is down" % ( controller.index ) )
253 return EventStates().ABORT
254 self.CLIIndex = index
255 if len( args ) == 4 and args[ 3 ] == 'bidirectional':
256 # Install point intents for both directions
257 resultA = self.startPointIntentEvent()
258 [ self.deviceA, self.deviceB ] = [ self.deviceB, self.deviceA ]
259 resultB = self.startPointIntentEvent()
260 if resultA == EventStates().PASS and resultB == EventStates().PASS:
261 return EventStates().PASS
262 else:
263 return EventStates().FAIL
264 else:
You Wangdb927a52016-02-26 11:03:28 -0800265 return self.startPointIntentEvent()
266
267class AddPointIntent( PointIntentEvent ):
268 """
269 Add a point-to-point intent
270 """
271 def __init__( self ):
272 PointIntentEvent.__init__( self )
273 self.typeString = main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeString' ]
274 self.typeIndex= int( main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeIndex' ] )
275
276 def startPointIntentEvent( self ):
You Wang7a27f3a2016-07-05 10:12:27 -0700277 try:
278 assert self.deviceA != None and self.deviceB != None
279 controller = main.controllers[ self.CLIIndex - 1 ]
280 # TODO: the following check only work when we use default port number for point intents
281 # Check whether there already exists some intent for the device pair
282 # For now we should avoid installing overlapping intents
283 for intent in main.intents:
284 if not intent.type == 'INTENT_POINT':
285 continue
286 if intent.deviceA == self.deviceA and intent.deviceB == self.deviceB:
287 main.log.warn( self.typeString + " - find an exiting intent for the device pair, abort installation" )
288 return EventStates().ABORT
289 controller = main.controllers[ self.CLIIndex - 1 ]
290 with controller.CLILock:
291 # TODO: handle the case that multiple hosts attach to one device
292 srcMAC = ""
293 dstMAC = ""
294 if len( self.deviceA.hosts ) > 0:
295 srcMAC = self.deviceA.hosts[ 0 ].mac
296 if len( self.deviceB.hosts ) > 0:
297 dstMAC = self.deviceB.hosts[ 0 ].mac
298 id = controller.CLI.addPointIntent( self.deviceA.dpid, self.deviceB.dpid,
299 1, 1, '', srcMAC, dstMAC )
300 if id == None:
301 main.log.warn( self.typeString + " - add point intent failed" )
302 return EventStates().FAIL
303 with main.variableLock:
304 newPointIntent = PointIntent( id, self.deviceA, self.deviceB )
305 if self.deviceA.isDown() or self.deviceB.isDown() or self.deviceA.isRemoved() or self.deviceB.isRemoved():
306 newPointIntent.setFailed()
307 main.intents.append( newPointIntent )
308 # Update host connectivity status
309 for hostA in self.deviceA.hosts:
310 for hostB in self.deviceB.hosts:
311 hostA.correspondents.append( hostB )
312 return EventStates().PASS
313 except Exception:
314 main.log.warn( "Caught exception, aborting event" )
315 return EventStates().ABORT
You Wangdb927a52016-02-26 11:03:28 -0800316
317class DelPointIntent( PointIntentEvent ):
318 """
319 Delete a point-to-point intent
320 """
321 def __init__( self ):
322 PointIntentEvent.__init__( self )
323 self.typeString = main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeString' ]
324 self.typeIndex= int( main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeIndex' ] )
325
326 def startPointIntentEvent( self ):
You Wang7a27f3a2016-07-05 10:12:27 -0700327 try:
328 assert self.deviceA != None and self.deviceB != None
329 targetIntent = None
330 for intent in main.intents:
331 if not intent.type == 'INTENT_POINT':
332 continue
333 if intent.deviceA == self.deviceA and intent.deviceB == self.deviceB:
334 targetIntent = intent
335 break
336 if targetIntent == None:
337 main.log.warn( self.typeString + " - intent does not exist" )
338 return EventStates().FAIL
339 controller = main.controllers[ self.CLIIndex - 1 ]
340 with controller.CLILock:
341 result = controller.CLI.removeIntent( targetIntent.id, purge=True )
342 if result == None or result == main.FALSE:
343 main.log.warn( self.typeString + " - delete point intent failed" )
344 return EventStates().FAIL
345 with main.variableLock:
346 main.intents.remove( targetIntent )
347 # Update host connectivity status
348 for hostA in self.deviceA.hosts:
349 for hostB in self.deviceB.hosts:
350 hostA.correspondents.remove( hostB )
351 return EventStates().PASS
352 except Exception:
353 main.log.warn( "Caught exception, aborting event" )
354 return EventStates().ABORT