blob: 22380cfc8b60a9b13350977ee07c857209cc7126 [file] [log] [blame]
You Wangdb927a52016-02-26 11:03:28 -08001"""
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07002Copyright 2016 Open Networking Foundation ( ONF )
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -07003
4Please refer questions to either the onos test mailing list at <onos-test@onosproject.org>,
5the System Testing Plans and Results wiki page at <https://wiki.onosproject.org/x/voMg>,
6or the System Testing Guide page at <https://wiki.onosproject.org/x/WYQg>
7
8 TestON is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070011 ( at your option ) any later version.
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -070012
13 TestON is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with TestON. If not, see <http://www.gnu.org/licenses/>.
20"""
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -070021"""
You Wangdb927a52016-02-26 11:03:28 -080022This file contains classes for CHOTestMonkey that are related to check event
23Author: you@onlab.us
24"""
25from tests.CHOTestMonkey.dependencies.events.Event import EventType, EventStates, Event
26
Jon Hall2bb3e212017-05-24 17:07:25 -070027
You Wangdb927a52016-02-26 11:03:28 -080028class CheckEvent( Event ):
Jon Hall2bb3e212017-05-24 17:07:25 -070029
You Wangdb927a52016-02-26 11:03:28 -080030 def __init__( self ):
31 Event.__init__( self )
32
33 def startCheckEvent( self ):
34 return EventStates().PASS
35
36 def startEvent( self, args ):
37 with self.eventLock:
You Wang52163202016-07-14 16:37:15 -070038 main.log.info( "Event recorded: {} {}".format( self.typeIndex, self.typeString ) )
You Wangdb927a52016-02-26 11:03:28 -080039 result = self.startCheckEvent()
40 return result
41
Jon Hall2bb3e212017-05-24 17:07:25 -070042
You Wangdb927a52016-02-26 11:03:28 -080043class IntentCheck( CheckEvent ):
Jon Hall2bb3e212017-05-24 17:07:25 -070044
You Wangdb927a52016-02-26 11:03:28 -080045 def __init__( self ):
46 CheckEvent.__init__( self )
47 self.typeString = main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeString' ]
48 self.typeIndex = int( main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeIndex' ] )
49
50 def startCheckEvent( self, args=None ):
51 checkResult = EventStates().PASS
You Wang58aa11e2016-05-17 10:35:44 -070052 intentDict = {}
You Wangdb927a52016-02-26 11:03:28 -080053 for intent in main.intents:
You Wang58aa11e2016-05-17 10:35:44 -070054 intentDict[ intent.id ] = intent.expectedState
You Wangdb927a52016-02-26 11:03:28 -080055 for controller in main.controllers:
56 if controller.isUp():
57 with controller.CLILock:
You Wang58aa11e2016-05-17 10:35:44 -070058 intentState = controller.CLI.compareIntent( intentDict )
You Wangdb927a52016-02-26 11:03:28 -080059 if not intentState:
You Wang58aa11e2016-05-17 10:35:44 -070060 main.log.warn( "Intent Check - not all intent ids and states match that on ONOS%s" % ( controller.index ) )
You Wange8c2b042019-01-22 15:07:25 -080061 # FIXME: ONOS leaves intents as WITHDRAWN state occasionally and we don't consider that as a FAIL for now
62 # checkResult = EventStates().FAIL
You Wang58aa11e2016-05-17 10:35:44 -070063 return checkResult
64
Jon Hall2bb3e212017-05-24 17:07:25 -070065
You Wang58aa11e2016-05-17 10:35:44 -070066class FlowCheck( CheckEvent ):
Jon Hall2bb3e212017-05-24 17:07:25 -070067
You Wang58aa11e2016-05-17 10:35:44 -070068 def __init__( self ):
69 CheckEvent.__init__( self )
70 self.typeString = main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeString' ]
71 self.typeIndex = int( main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeIndex' ] )
72
73 def startCheckEvent( self, args=None ):
74 import json
75 checkResult = EventStates().PASS
You Wang3c276252016-09-21 15:21:36 -070076 if main.enableIPv6:
You Wang62e1cf62016-09-22 17:13:03 -070077 coreFlowNum = int( main.params[ 'EVENT' ][ 'FlowCheck' ][ 'coreFlowNum6' ] )
You Wang3c276252016-09-21 15:21:36 -070078 else:
You Wang62e1cf62016-09-22 17:13:03 -070079 coreFlowNum = int( main.params[ 'EVENT' ][ 'FlowCheck' ][ 'coreFlowNum' ] )
You Wang58aa11e2016-05-17 10:35:44 -070080 for controller in main.controllers:
81 if controller.isUp():
82 with controller.CLILock:
You Wang3c276252016-09-21 15:21:36 -070083 # Check core flow number
84 for device in main.devices:
85 if device.isRemoved():
86 continue
87 coreFlowNumOnos = controller.CLI.flowAddedCount( device.dpid, core=True )
Jon Hall2bb3e212017-05-24 17:07:25 -070088 if coreFlowNumOnos is None:
You Wang3c276252016-09-21 15:21:36 -070089 main.log.warn( "Flow Check - error when trying to get flow number of %s on ONOS%s" % ( device.dpid, controller.index ) )
90 checkResult = EventStates().FAIL
91 else:
92 coreFlowNumOnos = int( coreFlowNumOnos )
93 if coreFlowNumOnos != coreFlowNum:
94 main.log.warn( "Flow Check - core flow number of %s on ONOS%s is %s" % ( device.dpid, controller.index, coreFlowNumOnos ) )
95 checkResult = EventStates().FAIL
96 # Get flows for comparison
You Wang58aa11e2016-05-17 10:35:44 -070097 flows = controller.CLI.flows()
98 try:
99 flows = json.loads( flows )
100 except ( TypeError, ValueError ):
101 main.log.exception( "Flow Check - Object not as expected: {!r}".format( flows ) )
102 return EventStates().FAIL
103 # Compare flow IDs in ONOS and Mininet
104 flowIDList = []
105 for item in flows:
106 for flow in item[ "flows" ]:
107 flowIDList.append( hex( int( flow[ 'id' ] ) ) )
108 main.log.info( "Flow Check - current flow number on ONOS%s: %s" % ( controller.index, len( flowIDList ) ) )
109 switchList = []
110 for device in main.devices:
111 switchList.append( device.name )
112 with main.mininetLock:
113 flowCompareResult = main.Mininet1.checkFlowId( switchList, flowIDList, debug=False )
114 if not flowCompareResult:
115 main.log.warn( "Flow Check - flows on ONOS%s do not match that in Mininet" % ( controller.index ) )
116 checkResult = EventStates().FAIL
117 # Check flow state
118 flowState = controller.CLI.checkFlowsState( isPENDING=False )
119 if not flowState:
120 main.log.warn( "Flow Check - not all flows are in ADDED state on ONOS%s" % ( controller.index ) )
121 checkResult = EventStates().FAIL
You Wangdb927a52016-02-26 11:03:28 -0800122 return checkResult
123
Jon Hall2bb3e212017-05-24 17:07:25 -0700124
You Wangdb927a52016-02-26 11:03:28 -0800125class TopoCheck( CheckEvent ):
Jon Hall2bb3e212017-05-24 17:07:25 -0700126
You Wangdb927a52016-02-26 11:03:28 -0800127 def __init__( self ):
128 CheckEvent.__init__( self )
129 self.typeString = main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeString' ]
130 self.typeIndex = int( main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeIndex' ] )
131
132 def startCheckEvent( self, args=None ):
133 import json
134 checkResult = EventStates().PASS
135 upLinkNum = 0
136 upDeviceNum = 0
You Wanga9a5e002019-01-31 12:33:26 -0800137 upHostList = []
You Wangdb927a52016-02-26 11:03:28 -0800138 with main.variableLock:
139 for link in main.links:
140 if not link.isDown() and not link.isRemoved():
141 upLinkNum += 1
142 for device in main.devices:
143 if not device.isDown() and not device.isRemoved():
144 upDeviceNum += 1
145 for host in main.hosts:
146 if not host.isDown() and not host.isRemoved():
You Wanga9a5e002019-01-31 12:33:26 -0800147 upHostList.append( host )
You Wangdb927a52016-02-26 11:03:28 -0800148 clusterNum = 1
You Wanga9a5e002019-01-31 12:33:26 -0800149 # Verify host IPs
150 if hasattr( main, "expectedHosts" ):
151 for host in upHostList:
152 ipResult = main.Mininet1.verifyHostIp( hostList=[ host.name ],
153 prefix=main.expectedHosts[ 'network' ][ host.name ],
154 update=False )
155 if not ipResult:
156 checkResult = EventStates().FAIL
157 main.log.warn( "Topo Check - Failed to verify IP address on host %s" % ( host.name ) )
158 '''
You Wang221db322016-06-03 15:45:52 -0700159 with main.mininetLock:
You Wang7d14d642019-01-23 15:10:08 -0800160 graphDictMininet = main.Mininet1.getGraphDict( useId=True, switchClasses=r"(OVSSwitch)",
161 excludeNodes=[ 'bgp', 'cs', 'nat', 'dhcp', 'r' ] )
You Wanga9a5e002019-01-31 12:33:26 -0800162 '''
You Wangdb927a52016-02-26 11:03:28 -0800163 for controller in main.controllers:
164 if controller.isUp():
165 with controller.CLILock:
You Wang7d14d642019-01-23 15:10:08 -0800166 '''
Flavio Castro82ee2f62016-06-07 15:04:12 -0700167 topoState = controller.CLI.checkStatus( upDeviceNum, upLinkNum )
You Wang7d14d642019-01-23 15:10:08 -0800168 if not topoState:
169 main.log.warn( "Topo Check - link or device number discoverd by ONOS%s is incorrect" % ( controller.index ) )
170 checkResult = EventStates().FAIL
You Wang221db322016-06-03 15:45:52 -0700171 # Compare ONOS and Mininet topologies
172 graphDictONOS = controller.CLI.getGraphDict()
173 compareResult = main.graph.compareGraphs( graphDictONOS, graphDictMininet )
174 if not compareResult:
175 checkResult = EventStates().FAIL
176 main.log.warn( "Topo Check - ONOS and Mininet topologies do not match" )
You Wang7d14d642019-01-23 15:10:08 -0800177 '''
You Wang58aa11e2016-05-17 10:35:44 -0700178 try:
You Wang221db322016-06-03 15:45:52 -0700179 # Check links
You Wang58aa11e2016-05-17 10:35:44 -0700180 links = controller.CLI.links()
181 links = json.loads( links )
182 if not len( links ) == upLinkNum:
183 checkResult = EventStates().FAIL
184 main.log.warn( "Topo Check - link number discoverd by ONOS%s is incorrect: %s expected and %s actual" % ( controller.index, upLinkNum, len( links ) ) )
185 # Check devices
186 devices = controller.CLI.devices()
187 devices = json.loads( devices )
188 availableDeviceNum = 0
189 for device in devices:
Jon Hall2bb3e212017-05-24 17:07:25 -0700190 if device[ 'available' ]:
You Wang58aa11e2016-05-17 10:35:44 -0700191 availableDeviceNum += 1
192 if not availableDeviceNum == upDeviceNum:
193 checkResult = EventStates().FAIL
194 main.log.warn( "Topo Check - device number discoverd by ONOS%s is incorrect: %s expected and %s actual" % ( controller.index, upDeviceNum, availableDeviceNum ) )
195 # Check hosts
196 hosts = controller.CLI.hosts()
197 hosts = json.loads( hosts )
You Wang7d14d642019-01-23 15:10:08 -0800198 if hasattr( main, "expectedHosts" ):
199 hosts = [ host for host in hosts if host[ 'id' ] in main.expectedHosts[ 'onos' ].keys() ]
You Wanga9a5e002019-01-31 12:33:26 -0800200 if not len( hosts ) == len( upHostList ):
You Wang7d14d642019-01-23 15:10:08 -0800201 # checkResult = EventStates().FAIL
You Wanga9a5e002019-01-31 12:33:26 -0800202 main.log.warn( "Topo Check - host number discoverd by ONOS%s is incorrect: %s expected and %s actual" % ( controller.index, len( upHostList ), len( hosts ) ) )
203 # Check Host IPs
204 if hasattr( main, "expectedHosts" ):
205 for host in upHostList:
206 ipResult = controller.CLI.verifyHostIp( hostList=[ host.id ],
207 prefix=main.expectedHosts[ 'onos' ][ host.id ] )
208 if not ipResult:
209 checkResult = EventStates().FAIL
210 main.log.warn( "Topo Check - ONOS%s failed to verify IP address on host %s" % ( controller.index, host.id ) )
You Wang58aa11e2016-05-17 10:35:44 -0700211 # Check clusters
212 clusters = controller.CLI.clusters()
213 clusters = json.loads( clusters )
214 if not len( clusters ) == clusterNum:
215 checkResult = EventStates().FAIL
216 main.log.warn( "Topo Check - cluster number discoverd by ONOS%s is incorrect: %s expected and %s actual" % ( controller.index, clusterNum, len( clusters ) ) )
217 except ( TypeError, ValueError ):
218 main.log.exception( "Flow Check - Object not as expected" )
219 return EventStates().FAIL
You Wangdb927a52016-02-26 11:03:28 -0800220 return checkResult
221
Jon Hall2bb3e212017-05-24 17:07:25 -0700222
You Wangdb927a52016-02-26 11:03:28 -0800223class ONOSCheck( CheckEvent ):
Jon Hall2bb3e212017-05-24 17:07:25 -0700224
You Wangdb927a52016-02-26 11:03:28 -0800225 def __init__( self ):
226 CheckEvent.__init__( self )
227 self.typeString = main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeString' ]
Jon Hall2bb3e212017-05-24 17:07:25 -0700228 self.typeIndex = int( main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeIndex' ] )
You Wangdb927a52016-02-26 11:03:28 -0800229
230 def startCheckEvent( self, args=None ):
231 import json
232 checkResult = EventStates().PASS
233 topics = []
234 # TODO: Other topics?
235 for i in range( 14 ):
Jon Hall8dafdcc2016-09-16 10:21:25 -0700236 topics.append( "work-partition-" + str( i ) )
You Wangdb927a52016-02-26 11:03:28 -0800237 dpidToAvailability = {}
238 dpidToMaster = {}
239 for device in main.devices:
240 if device.isDown() or device.isRemoved():
241 dpidToAvailability[ device.dpid ] = False
242 else:
243 dpidToAvailability[ device.dpid ] = True
244 dpidToMaster[ device.dpid ] = 'unknown'
245 # Check mastership, leaders and node states on each controller node
246 for controller in main.controllers:
247 if controller.isUp():
248 # Check mastership
You Wang58aa11e2016-05-17 10:35:44 -0700249 try:
250 with controller.CLILock:
251 roles = controller.CLI.roles()
252 roles = json.loads( roles )
253 for device in roles:
254 dpid = device[ 'id' ]
255 if dpidToMaster[ dpid ] == 'unknown':
256 dpidToMaster[ dpid ] = device[ 'master' ]
257 elif dpidToMaster[ dpid ] != device[ 'master' ]:
258 checkResult = EventStates().FAIL
259 main.log.warn( "ONOS Check - Mastership of %s on ONOS%s is inconsistent with that on ONOS1" % ( dpid, controller.index ) )
260 if dpidToAvailability[ dpid ] and device[ 'master' ] == "none":
261 checkResult = EventStates().FAIL
262 main.log.warn( "ONOS Check - Device %s has no master on ONOS%s" % ( dpid, controller.index ) )
263 # Check leaders
264 with controller.CLILock:
265 leaders = controller.CLI.leaders()
266 leaders = json.loads( leaders )
Jon Hall2bb3e212017-05-24 17:07:25 -0700267 ONOSTopics = [ j[ 'topic' ] for j in leaders ]
You Wang58aa11e2016-05-17 10:35:44 -0700268 for topic in topics:
269 if topic not in ONOSTopics:
270 checkResult = EventStates().FAIL
271 main.log.warn( "ONOS Check - Topic %s not in leaders on ONOS%s" % ( topic, controller.index ) )
272 # Check node state
273 with controller.CLILock:
274 nodes = controller.CLI.nodes()
275 nodes = json.loads( nodes )
276 ipToState = {}
277 for node in nodes:
278 ipToState[ node[ 'ip' ] ] = node[ 'state' ]
279 for c in main.controllers:
280 if c.isUp() and ipToState[ c.ip ] == 'READY':
281 pass
You Wange8c2b042019-01-22 15:07:25 -0800282 elif not c.isUp() and c.ip not in ipToState.keys():
You Wang58aa11e2016-05-17 10:35:44 -0700283 pass
284 else:
285 checkResult = EventStates().FAIL
286 main.log.warn( "ONOS Check - ONOS%s shows wrong node state: ONOS%s is %s but state is %s" % ( controller.index, c.index, c.status, ipToState[ c.ip ] ) )
287 # TODO: check partitions?
288 except ( TypeError, ValueError ):
289 main.log.exception( "ONOS Check - Object not as expected" )
290 return EventStates().FAIL
You Wange8c2b042019-01-22 15:07:25 -0800291 except Exception as e:
292 main.log.exception( "ONOS Check - Uncaught Exception: {}".format( e ) )
293 return EventStates().FAIL
You Wangdb927a52016-02-26 11:03:28 -0800294 return checkResult
295
Jon Hall2bb3e212017-05-24 17:07:25 -0700296
You Wangdb927a52016-02-26 11:03:28 -0800297class TrafficCheck( CheckEvent ):
Jon Hall2bb3e212017-05-24 17:07:25 -0700298
You Wangdb927a52016-02-26 11:03:28 -0800299 def __init__( self ):
300 CheckEvent.__init__( self )
301 self.typeString = main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeString' ]
Jon Hall2bb3e212017-05-24 17:07:25 -0700302 self.typeIndex = int( main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeIndex' ] )
You Wangdb927a52016-02-26 11:03:28 -0800303
304 def startCheckEvent( self, args=None ):
305 checkResult = EventStates().PASS
306 pool = []
307 wait = int( main.params[ 'EVENT' ][ 'TrafficCheck' ][ 'pingWait' ] )
308 timeout = int( main.params[ 'EVENT' ][ 'TrafficCheck' ][ 'pingTimeout' ] )
309 dstIPv4List = {}
310 dstIPv6List = {}
311 upHosts = []
312 for host in main.hosts:
313 if host.isUp():
314 upHosts.append( host )
You Wang7d14d642019-01-23 15:10:08 -0800315 import re
You Wangdb927a52016-02-26 11:03:28 -0800316 for host in upHosts:
317 dstIPv4List[ host.index ] = []
318 dstIPv6List[ host.index ] = []
319 for correspondent in host.correspondents:
Jon Hall2bb3e212017-05-24 17:07:25 -0700320 if correspondent not in upHosts:
You Wangdb927a52016-02-26 11:03:28 -0800321 continue
322 for ipAddress in correspondent.ipAddresses:
You Wang7d14d642019-01-23 15:10:08 -0800323 if re.match( str( main.params[ 'TEST' ][ 'ipv6Regex' ] ), ipAddress ):
You Wangdb927a52016-02-26 11:03:28 -0800324 dstIPv6List[ host.index ].append( ipAddress )
You Wang7d14d642019-01-23 15:10:08 -0800325 elif re.match( str( main.params[ 'TEST' ][ 'ipv4Regex' ] ), ipAddress ):
You Wangdb927a52016-02-26 11:03:28 -0800326 dstIPv4List[ host.index ].append( ipAddress )
You Wang7d14d642019-01-23 15:10:08 -0800327 if dstIPv4List[ host.index ]:
328 main.log.debug( "Check ping from host {} to {}".format( host.name, dstIPv4List[ host.index ] ) )
You Wangdb927a52016-02-26 11:03:28 -0800329 thread = main.Thread( target=host.handle.pingHostSetAlternative,
330 threadID=main.threadID,
331 name="pingHostSetAlternative",
332 args=[ dstIPv4List[ host.index ], 1 ] )
333 pool.append( thread )
334 thread.start()
335 with main.variableLock:
336 main.threadID += 1
337 for thread in pool:
338 thread.join( 10 )
339 if not thread.result:
340 checkResult = EventStates().FAIL
341 main.log.warn( "Traffic Check - ping failed" )
342
343 if not main.enableIPv6:
344 return checkResult
345 # Check ipv6 ping
346 for host in upHosts:
You Wang7d14d642019-01-23 15:10:08 -0800347 if dstIPv6List[ host.index ]:
348 main.log.debug( "Check ping from host {} to {}".format( host.name, dstIPv6List[ host.index ] ) )
You Wangdb927a52016-02-26 11:03:28 -0800349 thread = main.Thread( target=host.handle.pingHostSetAlternative,
350 threadID=main.threadID,
351 name="pingHostSetAlternative",
352 args=[ dstIPv6List[ host.index ], 1, True ] )
353 pool.append( thread )
354 thread.start()
355 with main.variableLock:
356 main.threadID += 1
357 for thread in pool:
358 thread.join( 10 )
359 if not thread.result:
360 checkResult = EventStates().FAIL
361 main.log.warn( "Traffic Check - ping6 failed" )
362 return checkResult
Devin Limf0822182017-09-12 14:52:57 -0700363
364class RaftLogSizeCheck( CheckEvent ):
365
366 def __init__( self ):
367 CheckEvent.__init__( self )
368 self.typeString = main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeString' ]
369 self.typeIndex = int( main.params[ 'EVENT' ][ self.__class__.__name__ ][ 'typeIndex' ] )
370
371 def startCheckEvent( self, args=None ):
372 checkResult = EventStates().PASS
373 main.log.info( "Starting checking Raft Log size" )
374 if not main.Cluster.checkPartitionSize():
375 checkResult = EventStates().FAIL
376 main.log.warn( "Raft Log Size Check - Raft log grew too big" )
377
378 return checkResult