blob: 46b37e7963b219ef92d5cffc9821aad70ccfe562 [file] [log] [blame]
You Wangdb927a52016-02-26 11:03:28 -08001"""
2This file contains classes for CHOTestMonkey that are related to network event
3Author: you@onlab.us
4"""
5from tests.CHOTestMonkey.dependencies.events.Event import EventType, EventStates, Event
6from tests.CHOTestMonkey.dependencies.elements.NetworkElement import NetworkElement, Device, Host, Link
7from tests.CHOTestMonkey.dependencies.GraphHelper import GraphHelper
8
9class LinkEvent( Event ):
10 def __init__( self ):
11 Event.__init__( self )
12 self.linkA = None
13 self.linkB = None
14
15 def startLinkEvent( self ):
16 return EventStates().PASS
17
18 def startEvent( self, args ):
19 """
20 args are the names of the two link ends, e.g. ['s1', 's2']
21 """
22 with self.eventLock:
23 main.log.info( "%s - starting event" % ( self.typeString ) )
24 if len( args ) < 2:
25 main.log.warn( "%s - Not enough arguments: %s" % ( self.typeString, args ) )
26 return EventStates().ABORT
27 elif len( args ) > 2:
28 main.log.warn( "%s - Too many arguments: %s" % ( self.typeString, args ) )
29 return EventStates().ABORT
30 if args[ 0 ] == 'random' or args[ 1 ] == 'random':
31 import random
32 if self.typeIndex == EventType().NETWORK_LINK_DOWN:
33 with main.variableLock:
34 graphHelper = GraphHelper()
35 availableLinks = graphHelper.getNonCutEdges()
36 if len( availableLinks ) == 0:
37 main.log.warn( "All links are cut edges, aborting event" )
38 return EventStates().ABORT
39 linkList = random.sample( availableLinks, 1 )
40 self.linkA = linkList[ 0 ]
41 self.linkB = linkList[ 0 ].backwardLink
42 elif self.typeIndex == EventType().NETWORK_LINK_UP:
43 with main.variableLock:
44 downLinks = []
45 for link in main.links:
46 if link.isDown():
47 downLinks.append( link )
48 if len( downLinks ) == 0:
49 main.log.warn( "None of the links are in 'down' state, aborting event" )
50 return EventStates().ABORT
51 linkList = random.sample( downLinks, 1 )
52 self.linkA = linkList[ 0 ]
53 self.linkB = linkList[ 0 ].backwardLink
54 elif args[ 0 ] == args[ 1 ]:
55 main.log.warn( "%s - invalid arguments: %s" % ( self.typeString, args ) )
56 return EventStates().ABORT
57 else:
58 for link in main.links:
59 if link.deviceA.name == args[ 0 ] and link.deviceB.name == args[ 1 ]:
60 self.linkA = link
61 elif link.deviceA.name == args[ 1 ] and link.deviceB.name == args[ 0 ]:
62 self.linkB = link
63 if self.linkA != None and self.linkB != None:
64 break
65 if self.linkA == None or self.linkB == None:
66 main.log.warn( "Bidirectional link %s - %s does not exist: " % ( args[ 0 ], args[ 1 ] ) )
67 return EventStates().ABORT
68 main.log.debug( "%s - %s" % ( self.typeString, self.linkA ) )
69 return self.startLinkEvent()
70
71class LinkDown( LinkEvent ):
72 """
73 Generate a link down event giving the two ends of the link
74 """
75 def __init__( self ):
76 LinkEvent.__init__( self )
77 self.typeString = main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeString' ]
78 self.typeIndex = int( main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeIndex' ] )
79
80 def startLinkEvent( self ):
81 # TODO: do we need to handle a unidirectional link?
82 assert self.linkA != None and self.linkB != None
83 with main.variableLock:
84 if self.linkA.isDown() or self.linkB.isDown():
85 main.log.warn( "Link Down - link already down" )
86 return EventStates().ABORT
87 elif self.linkA.isRemoved() or self.linkB.isRemoved():
88 main.log.warn( "Link Down - link has been removed" )
89 return EventStates().ABORT
90 with main.mininetLock:
91 result = main.Mininet1.link( END1=self.linkA.deviceA.name,
92 END2=self.linkA.deviceB.name,
93 OPTION="down")
94 if not result:
95 main.log.warn( "%s - failed to bring down link" % ( self.typeString ) )
96 return EventStates().FAIL
97 with main.variableLock:
98 self.linkA.bringDown()
99 self.linkB.bringDown()
100 return EventStates().PASS
101
102class LinkUp( LinkEvent ):
103 """
104 Generate a link up event giving the two ends of the link
105 """
106 def __init__( self ):
107 LinkEvent.__init__( self )
108 self.typeString = main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeString' ]
109 self.typeIndex = int( main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeIndex' ] )
110
111 def startLinkEvent( self ):
112 assert self.linkA != None and self.linkB != None
113 with main.variableLock:
114 if self.linkA.isUp() or self.linkB.isUp():
115 main.log.warn( "Link Up - link already up" )
116 return EventStates().ABORT
117 if self.linkA.isRemoved() or self.linkB.isRemoved():
118 main.log.warn( "Link Up - link has been removed" )
119 return EventStates().ABORT
120 with main.mininetLock:
121 result = main.Mininet1.link( END1=self.linkA.deviceA.name,
122 END2=self.linkA.deviceB.name,
123 OPTION="up")
124 if not result:
125 main.log.warn( "%s - failed to bring up link" % ( self.typeString ) )
126 return EventStates().FAIL
127 with main.variableLock:
128 self.linkA.bringUp()
129 self.linkB.bringUp()
130 return EventStates().PASS
131
132class DeviceEvent( Event ):
133 def __init__( self ):
134 Event.__init__( self )
135 self.device = None
136
137 def startDeviceEvent( self ):
138 return EventStates().PASS
139
140 def startEvent( self, args ):
141 """
142 args are the names of the device, e.g. 's1'
143 """
144 with self.eventLock:
145 main.log.info( "%s - starting event" % ( self.typeString ) )
146 if len( args ) < 1:
147 main.log.warn( "%s - Not enough arguments: %s" % ( self.typeString, args ) )
148 return EventStates().ABORT
149 elif len( args ) > 1:
150 main.log.warn( "%s - Too many arguments: %s" % ( self.typeString, args ) )
151 return EventStates().ABORT
152 if args[ 0 ] == 'random':
153 import random
154 if self.typeIndex == EventType().NETWORK_DEVICE_DOWN:
155 with main.variableLock:
156 graphHelper = GraphHelper()
157 availableDevices = graphHelper.getNonCutVertices()
158 if len( availableDevices ) == 0:
159 main.log.warn( "All devices are cut vertices, aborting event" )
160 return EventStates().ABORT
161 deviceList = random.sample( availableDevices, 1 )
162 self.device = deviceList[ 0 ]
163 elif self.typeIndex == EventType().NETWORK_DEVICE_UP:
164 with main.variableLock:
165 removedDevices = []
166 for device in main.devices:
167 if device.isRemoved():
168 removedDevices.append( device )
169 if len( removedDevices ) == 0:
170 main.log.warn( "None of the devices are removed, aborting event" )
171 return EventStates().ABORT
172 deviceList = random.sample( removedDevices, 1 )
173 self.device = deviceList[ 0 ]
174 else:
175 for device in main.devices:
176 if device.name == args[ 0 ]:
177 self.device = device
178 if self.device == None:
179 main.log.warn( "Device %s does not exist: " % ( args[ 0 ] ) )
180 return EventStates().ABORT
181 main.log.debug( "%s - %s" % ( self.typeString, self.device ) )
182 return self.startDeviceEvent()
183
184class DeviceDown( DeviceEvent ):
185 """
186 Generate a device down event (which actually removes this device for now) giving its name
187 """
188 def __init__( self ):
189 DeviceEvent.__init__( self )
190 self.typeString = main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeString' ]
191 self.typeIndex = int( main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeIndex' ] )
192
193 def startDeviceEvent( self ):
194 assert self.device != None
195 with main.variableLock:
196 if self.device.isRemoved():
197 main.log.warn( "Device Down - device has been removed" )
198 return EventStates().ABORT
199 with main.mininetLock:
200 result = main.Mininet1.delSwitch( self.device.name )
201 if not result:
202 main.log.warn( "%s - failed to bring down device" % ( self.typeString ) )
203 return EventStates().FAIL
204 with main.variableLock:
205 self.device.setRemoved()
206 for link in self.device.outgoingLinks:
207 link.setRemoved()
208 link.backwardLink.setRemoved()
209 for host in self.device.hosts:
210 host.setRemoved()
211 return EventStates().PASS
212
213class DeviceUp( DeviceEvent ):
214 """
215 Generate a device up event (which re-adds this device in case the device is removed) giving its name
216 """
217 def __init__( self ):
218 DeviceEvent.__init__( self )
219 self.typeString = main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeString' ]
220 self.typeIndex = int( main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeIndex' ] )
221
222 def startDeviceEvent( self ):
223 assert self.device != None
224 with main.variableLock:
225 if self.device.isUp():
226 main.log.warn( "Device Up - device already up" )
227 return EventStates().ABORT
228 # Re-add the device
229 with main.mininetLock:
230 result = main.Mininet1.addSwitch( self.device.name, dpid=self.device.dpid[3:] )
231 if not result:
232 main.log.warn( "%s - failed to re-add device" % ( self.typeString ) )
233 return EventStates().FAIL
234 with main.variableLock:
235 self.device.bringUp()
236 # Re-add links
237 # We add host-device links first since we did the same in mininet topology file
238 # TODO: a more rubust way is to add links according to the port info of the device
239 for host in self.device.hosts:
240 # Add host-device link
241 with main.mininetLock:
242 result = main.Mininet1.addLink( self.device.name, host.name )
243 if not result:
244 main.log.warn( "%s - failed to re-connect host %s to device" % ( self.typeString, host.name ) )
245 return EventStates().FAIL
246 for link in self.device.outgoingLinks:
247 neighbor = link.deviceB
248 # Skip bringing up any link that connecting this device to a removed neighbor
249 if neighbor.isRemoved():
250 continue
251 with main.mininetLock:
252 result = main.Mininet1.addLink( self.device.name, neighbor.name )
253 if not result:
254 main.log.warn( "%s - failed to re-add link to %s" % ( self.typeString, neighbor.name ) )
255 return EventStates().FAIL
256 with main.variableLock:
257 link.bringUp()
258 link.backwardLink.bringUp()
259 # Re-assign mastership for the device
260 with main.mininetLock:
261 main.Mininet1.assignSwController( sw=self.device.name, ip=main.onosIPs )
262 # Re-discover hosts
263 for host in self.device.hosts:
264 correspondent = None
265 for h in main.hosts:
266 if h.isUp() and h != host:
267 correspondent = h
268 break
269 if correspondent == None:
270 with main.mininetLock:
271 main.Mininet1.pingall()
272 if main.enableIPv6:
273 main.Mininet1.pingall( protocol="IPv6" )
274 else:
275 ipv4Addr = None
276 ipv6Addr = None
277 for ipAddress in correspondent.ipAddresses:
278 if ipAddress.startswith( str( main.params[ 'TEST' ][ 'ipv6Prefix' ] ) ) and ipv6Addr == None:
279 ipv6Addr = ipAddress
280 elif ipAddress.startswith( str( main.params[ 'TEST' ][ 'ipv4Prefix' ] ) ) and ipv4Addr == None:
281 ipv4Addr = ipAddress
282 assert ipv4Addr != None
283 host.handle.pingHostSetAlternative( [ ipv4Addr ], 1 )
284 if main.enableIPv6:
285 assert ipv6Addr != None
286 host.handle.pingHostSetAlternative( [ ipv6Addr ], 1, True )
287 with main.variableLock:
288 host.bringUp()
289 return EventStates().PASS