blob: 700008b0be72a2ae44e8dd1c10a6b7631e865c42 [file] [log] [blame]
Jeremy Ronquillo818bc7c2017-08-09 17:14:53 +00001"""
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07002Copyright 2017 Open Networking Foundation ( ONF )
Jeremy Ronquillo818bc7c2017-08-09 17:14:53 +00003
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 Ronquillo818bc7c2017-08-09 17:14:53 +000012
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 Ronquillo818bc7c2017-08-09 17:14:53 +000021class SCPFmastershipFailoverLat:
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070022
Jeremy Ronquillo818bc7c2017-08-09 17:14:53 +000023 def __init__( self ):
24 self.default = ''
25
26 def CASE0( self, main ):
27 import os
28 import imp
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070029 """
Jeremy Ronquillo818bc7c2017-08-09 17:14:53 +000030 - GIT
31 - BUILDING ONOS
32 Pull specific ONOS branch, then Build ONOS ono ONOS Bench.
33 This step is usually skipped. Because in a Jenkins driven automated
34 test env. We want Jenkins jobs to pull&build for flexibility to handle
35 different versions of ONOS.
36 - Construct tests variables
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070037 """
Jeremy Ronquillo818bc7c2017-08-09 17:14:53 +000038 try:
39 from tests.dependencies.ONOSSetup import ONOSSetup
40 main.testSetUp = ONOSSetup()
41 except ImportError:
42 main.log.error( "ONOSSetup not found. exiting the test" )
43 main.exit()
44 main.testSetUp.envSetupDescription()
45 stepResult = main.FALSE
46 try:
47 main.MN1Ip = main.params[ 'MN' ][ 'ip1' ]
48 main.cellName = main.params[ 'ENV' ][ 'cellName' ]
49 main.apps = main.params[ 'ENV' ][ 'cellApps' ]
50 main.scale = ( main.params[ 'SCALE' ] ).split( "," )
51 main.ofpRoleRequest = main.params[ 'TSHARK' ][ 'ofpRoleRequest' ]
52 main.tsharkResultPath = main.params[ 'TSHARK' ][ 'tsharkResultPath' ]
53 main.sampleSize = int( main.params[ 'TEST' ][ 'sampleSize' ] )
54 main.warmUp = int( main.params[ 'TEST' ][ 'warmUp' ] )
55 main.dbFileName = main.params[ 'DATABASE' ][ 'dbName' ]
56 main.maxScale = int( main.params[ 'max' ] )
57 main.timeout = int( main.params[ 'TIMEOUT' ][ 'timeout' ] )
58 main.MNSleep = int( main.params[ 'SLEEP' ][ 'mininet' ] )
59 main.recoverySleep = int( main.params[ 'SLEEP' ][ 'recovery' ] )
60 main.debug = main.params[ 'TEST' ][ 'debug' ]
61 main.failoverSleep = int( main.params[ 'SLEEP' ][ 'failover' ] )
62 main.switchID = main.params[ 'SWITCH' ][ 'id' ]
63 main.topologySwitchCount = main.params[ 'TOPOLOGY' ][ 'switchCount' ]
64 main.topologyType = main.params[ 'TOPOLOGY' ][ 'type' ]
65 main.nodeNumToKill = int( main.params[ 'KILL' ][ 'nodeNum' ] )
66 main.failPercent = float( main.params[ 'TEST' ][ 'failPercent' ] )
67
68 if main.debug == "True":
69 main.debug = True
70 else:
71 main.debug = False
72
73 stepResult = main.testSetUp.envSetup()
74 main.log.info( "Create Database file " + main.dbFileName )
75 resultsDB = open( main.dbFileName, "w+" )
76 resultsDB.close()
77
78 except Exception as e:
79 main.testSetUp.envSetupException( e )
80 main.testSetUp.evnSetupConclusion( stepResult )
81
Jeremy Ronquillo818bc7c2017-08-09 17:14:53 +000082 def CASE1( self, main ):
83 # Clean up test environment and set up
84 import time
You Wanga0f6ff62018-01-11 15:46:30 -080085 main.testSetUp.ONOSSetUp( main.Cluster, True,
Jeremy Ronquillo818bc7c2017-08-09 17:14:53 +000086 cellName=main.cellName, killRemoveMax=False )
87 try:
88 from tests.dependencies.utils import Utils
89 except ImportError:
90 main.log.error( "Utils not found exiting the test" )
91 main.exit()
92 try:
93 main.Utils
94 except ( NameError, AttributeError ):
95 main.Utils = Utils()
96 main.Utils.mininetCleanup( main.Mininet1 )
97
98 main.step( "Starting up Mininet from command." )
99
100 mnCmd = " mn " + " --topo " + main.topologyType + "," + main.topologySwitchCount
101 for ctrl in main.Cluster.active():
102 mnCmd += " --controller remote,ip=" + ctrl.ipAddress
103
104 stepResult = main.Mininet1.startNet( mnCmd=mnCmd )
105
106 utilities.assert_equals( expect=main.TRUE,
107 actual=stepResult,
108 onpass="Mininet was set up correctly.",
109 onfail="Mininet was NOT set up correctly." )
110
Jeremy Ronquillo818bc7c2017-08-09 17:14:53 +0000111 def CASE2( self, main ):
112 """
113 Kill ONOS node, and measure the latency for INSTANCE_DEACTIVATED, MASTER_CHANGED, and role request
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700114 ( tshark time ), then bring the node back up.
Jeremy Ronquillo818bc7c2017-08-09 17:14:53 +0000115 """
116 import time
117 import datetime
118 import numpy
119 from tests.HA.dependencies.HA import HA
120
121 main.HA = HA()
122
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700123 main.latencyData = { 'kill_to_deactivation': [],
124 'deactivation_to_role_request': [] }
Jeremy Ronquillo818bc7c2017-08-09 17:14:53 +0000125
126 main.failCounter = 0
127 passingResult = True
128 criticalError = False
129
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700130 main.step( "Gathering data starting with "
131 + str( main.warmUp )
132 + " warm ups and a sample size of "
133 + str( main.sampleSize ) )
Jeremy Ronquillo818bc7c2017-08-09 17:14:53 +0000134
135 for iteration in range( 0, main.sampleSize + main.warmUp ):
136
137 main.log.info( "==========================================" )
138 main.log.info( "================iteration:{}==============".format( str( iteration + 1 ) ) )
139
140 ip_address = main.Cluster.active( 0 ).ipAddress
141 strNodeNumToKill = str( main.nodeNumToKill )
142
143 main.log.info( "Assigning mastership to ONOS node " + strNodeNumToKill )
144 main.Cluster.active( 0 ).CLI.deviceRole( main.switchID, ip_address )
145
146 main.log.info( "Sleeping for " + str( main.recoverySleep ) + " seconds..." )
147 time.sleep( main.recoverySleep )
148 mastershipCheck = main.Cluster.active( 0 ).CLI.getMaster( main.switchID ) == ip_address
149
150 if not mastershipCheck:
151 main.log.warn( "Mastership is NOT as expected." )
152
153 with open( main.tsharkResultPath, "w" ) as tshark:
154 tshark.write( "" )
155 main.log.info( "Starting tshark capture." )
156 main.ONOSbench.tsharkGrep( main.ofpRoleRequest, main.tsharkResultPath )
157 time1 = time.time() * 1000.0
158
159 # Kill an ONOS node
160 main.log.info( "Killing ONOS node " + strNodeNumToKill + "." )
161 killresult = main.ONOSbench.onosKill( ip_address )
162 main.Cluster.runningNodes[ main.nodeNumToKill ].active = False
163
164 # Stop an ONOS node
165 main.log.info( "Stopping ONOS node " + strNodeNumToKill + "." )
166 stopresult = main.ONOSbench.onosStop( ip_address )
167
168 killStopResult = stopresult == killresult and True
169
170 if not killStopResult:
171 main.log.error( "ONOS node was NOT successfully stopped and killed." )
172 criticalError = True
173
174 time.sleep( main.failoverSleep )
175
176 # Stop tshark and get times
177 main.log.info( "Stopping tshark." )
178 main.ONOSbench.tsharkStop()
179
180 masterChangedLats = []
181 instanceDeactivatedLats = []
182
183 main.log.info( "Obtaining latencies from 'events' output." )
184 for CLInum in range( 0, main.Cluster.numCtrls - 1 ):
185 eventOutput = main.Cluster.active( CLInum ).CLI.events( args='-a' ).split( "\r\n" )
186 for line in reversed( eventOutput ):
You Wang4aa92722018-07-05 14:34:52 -0700187 timestamp = line[ :23 ] if line[ 19 ] != '-' else line[ :19 ] + '.000'
You Wangae564162018-08-22 14:27:38 -0700188 timestamp = float( datetime.datetime.strptime( timestamp, "%Y-%m-%dT%H:%M:%S.%f" ).strftime( '%s.%f' ) ) * 1000.0
189 if timestamp - time1 >= 0:
190 if "INSTANCE_DEACTIVATED" in line:
191 instanceDeactivatedLats.append( timestamp - time1 )
192 elif "MASTER_CHANGED" in line:
193 masterChangedLats.append( timestamp - time1 )
194 else:
Jeremy Ronquillo818bc7c2017-08-09 17:14:53 +0000195 break
196
You Wang96b3f162018-10-12 11:53:28 -0700197 if instanceDeactivatedLats and masterChangedLats:
198 instanceDeactivatedLats.sort()
199 masterChangedLats.sort()
200 instanceDeactivated = instanceDeactivatedLats[ 0 ]
201 masterChanged = masterChangedLats[ 0 ]
202 eventLatCheck = True
203 else:
204 eventLatCheck = False
Jeremy Ronquillo818bc7c2017-08-09 17:14:53 +0000205 main.log.warn( "Latencies were NOT obtained from 'events' successfully." )
206
207 main.log.info( "Obtain latency from tshark output." )
208 tsharkLatCheck = True
209 with open( main.tsharkResultPath, "r" ) as resultFile:
210 resultText = resultFile.readline()
211 main.log.info( "Capture result: " + resultText )
212 resultText = resultText.split()
213 if len( resultText ) > 1:
214 roleRequestLat = int( float( resultText[ 1 ] ) * 1000.0 ) - time1
215 resultFile.close()
216 else:
217 main.log.error( "Tshark output file is NOT as expected." )
218 tsharkLatCheck = False
219 if not tsharkLatCheck:
220 main.log.warn( "Latency was NOT obtained from tshark successfully." )
221
222 validDataCheck = False
223 if tsharkLatCheck:
224 main.log.info( "instanceDeactivated: " + str( instanceDeactivated ) )
You Wangae564162018-08-22 14:27:38 -0700225 main.log.info( "masterChanged: " + str( masterChanged ) )
226 main.log.info( "roleRequestLat: " + str( roleRequestLat ) )
Jeremy Ronquillo818bc7c2017-08-09 17:14:53 +0000227 if iteration >= main.warmUp:
228 main.log.info( "Verifying that the data are valid." ) # Don't record data during a warm-up
You Wangae564162018-08-22 14:27:38 -0700229 validDataCheck = roleRequestLat >= 0 and \
230 instanceDeactivated >= 0 and \
231 masterChanged >= 0
Jeremy Ronquillo818bc7c2017-08-09 17:14:53 +0000232 if not validDataCheck:
233 main.log.warn( "Data are NOT valid." )
234
235 if eventLatCheck and tsharkLatCheck and validDataCheck:
236 main.log.info( "Saving data..." )
You Wangae564162018-08-22 14:27:38 -0700237 if roleRequestLat >= instanceDeactivated:
238 main.latencyData[ 'kill_to_deactivation' ].append( instanceDeactivated )
239 main.latencyData[ 'deactivation_to_role_request' ].append( roleRequestLat - instanceDeactivated )
240 else:
241 main.latencyData[ 'kill_to_deactivation' ].append( roleRequestLat )
242 main.latencyData[ 'deactivation_to_role_request' ].append( 0 )
243 main.log.info( "kill_to_deactivation: " + str( main.latencyData[ 'kill_to_deactivation' ][ -1 ] ) )
244 main.log.info( "deactivation_to_role_request: " + str( main.latencyData[ 'deactivation_to_role_request' ][ -1 ] ) )
Jeremy Ronquillo818bc7c2017-08-09 17:14:53 +0000245
246 # Restart ONOS node
247 main.log.info( "Restart ONOS node " + strNodeNumToKill + " and checking status of restart." )
248 startResult = main.ONOSbench.onosStart( ip_address )
249
250 if not startResult:
251 main.log.error( "ONOS nodes NOT successfully started." )
252 criticalError = True
253
254 # Check if ONOS is up yet
255 main.log.info( "Checking if ONOS node " + strNodeNumToKill + " is up." )
256 upResult = main.ONOSbench.isup( ip_address )
257
258 if not upResult:
259 main.log.error( "ONOS did NOT successfully restart." )
260 criticalError = True
261
262 # Restart CLI
263 main.log.info( "Restarting ONOS node " + strNodeNumToKill + "'s main.CLI." )
264 cliResult = main.Cluster.active( main.nodeNumToKill ).CLI.startOnosCli( ip_address )
265 main.Cluster.runningNodes[ main.nodeNumToKill ] .active = True
266
267 if not cliResult:
268 main.log.error( "ONOS CLI did NOT successfully restart." )
269 criticalError = True
270
271 main.log.info( "Checking ONOS nodes." )
Devin Lim3ebd5e72017-11-14 10:38:00 -0800272 nodeResults = utilities.retry( main.Cluster.nodesCheck,
Jeremy Ronquillo818bc7c2017-08-09 17:14:53 +0000273 False,
Jeremy Ronquillo818bc7c2017-08-09 17:14:53 +0000274 sleep=1,
275 attempts=3 )
276
277 if not nodeResults:
278 main.log.error( "Nodes check NOT successful." )
279 criticalError = True
280
281 main.log.info( "Sleeping for " + str( main.recoverySleep ) + " seconds..." )
282 time.sleep( main.recoverySleep )
283
284 if not ( mastershipCheck and
285 eventLatCheck and
286 tsharkLatCheck and
287 validDataCheck ) and \
288 iteration >= main.warmUp:
289 main.failCounter += 1
290 main.log.warn( "Iteration failed. Failure count: " + str( main.failCounter ) )
291 if float( main.failCounter ) / float( main.sampleSize ) >= main.failPercent or criticalError:
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700292 main.log.error( str( main.failPercent * 100 )
293 + "% or more of data is invalid, or a critical error has occurred." )
Jeremy Ronquillo818bc7c2017-08-09 17:14:53 +0000294 passingResult = False
295 break
296
297 utilities.assert_equals( expect=True, actual=passingResult,
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700298 onpass="Node scaling "
299 + str( main.Cluster.numCtrls )
300 + " data gathering was successful.",
301 onfail="Node scaling "
302 + str( main.Cluster.numCtrls )
303 + " data gathering FAILED. Stopping test." )
Jeremy Ronquillo818bc7c2017-08-09 17:14:53 +0000304 if not passingResult:
305 main.cleanAndExit()
306
Jeremy Ronquillo818bc7c2017-08-09 17:14:53 +0000307 def CASE3( self, main ):
308 """
309 Write results to database file.
310 Omit this case if you don't want to write to database.
311 """
312 import numpy
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700313 result = { 'avg': {}, 'stddev': {} }
Jeremy Ronquillo818bc7c2017-08-09 17:14:53 +0000314
315 for i in main.latencyData:
316 result[ 'avg' ][ i ] = numpy.average( main.latencyData[ i ] )
317 result[ 'stddev' ][ i ] = numpy.std( main.latencyData[ i ] )
318
319 main.log.info( "result: " + str( result ) )
320 with open( main.dbFileName, "a" ) as dbFile:
321 strToWrite = str( main.Cluster.numCtrls ) + ",'baremetal1'"
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700322 strToWrite += ",'" + main.commit.split()[1] + "'"
Jeremy Ronquillo818bc7c2017-08-09 17:14:53 +0000323 for i in result:
324 for j in result[ i ]:
325 strToWrite += "," + str( result[ i ][ j ] )
326 strToWrite += "\n"
327 dbFile.write( strToWrite )
328 dbFile.close()