blob: 762035480a3977703ac4e6bd45ebe6819d88095b [file] [log] [blame]
kelvin-onlab1d381fe2015-07-14 16:24:56 -07001"""
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07002Copyright 2015 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"""
kelvin-onlab1d381fe2015-07-14 16:24:56 -070022 Wrapper function for FuncTopo
23 Includes onosclidriver and mininetclidriver functions
24"""
25import time
26import json
27import re
28
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070029
kelvin-onlab1d381fe2015-07-14 16:24:56 -070030def __init__( self ):
31 self.default = ''
32
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070033
Chiyu Chengb8c2c842016-10-05 12:40:49 -070034def getTimestampFromString( main, targetString ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070035 # Get time string from the target string
Chiyu Chengb8c2c842016-10-05 12:40:49 -070036 try:
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070037 assert isinstance( targetString, str )
Chiyu Chengb8c2c842016-10-05 12:40:49 -070038 timeString = targetString.split( ' | ' )
39 timeString = timeString[ 0 ]
40 from datetime import datetime
41 # convert time string to timestamp
42 t = datetime.strptime( timeString, "%Y-%m-%d %H:%M:%S,%f" )
43 import time
44 timestamp = time.mktime( t.timetuple() )
45 timestamp += int( t.microsecond / 1000 ) / 1000.0
46 return timestamp
47 except AssertionError:
48 main.log.error( "Got nothing firom log" )
49 return -1
50 except IndexError:
51 main.log.error( "Time string index error" )
52 return -1
53 except ValueError:
54 main.log.error( "Got wrong string from log" )
55 return -1
56
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070057
Chiyu Cheng899621b2016-11-14 11:14:48 -080058def getRoleRequestTimeFromTshark( main ):
59 try:
60 main.log.info( "Get role request time" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070061 with open( main.tsharkResultPath, "r" ) as resultFile:
Chiyu Cheng899621b2016-11-14 11:14:48 -080062 resultText = resultFile.readlines()
63 # select the last role request string
64 roleRequestString = resultText[ len( resultText ) - 1 ]
65 main.log.info( roleRequestString )
66 # get timestamp from role request string
67 roleRequestTime = roleRequestString.split( " " )
68 resultFile.close()
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070069 return float( roleRequestTime[ 1 ] )
Chiyu Cheng899621b2016-11-14 11:14:48 -080070 except IndexError:
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070071 main.log.error( "Got wrong role request string from Tshark file" )
Chiyu Cheng899621b2016-11-14 11:14:48 -080072 return -1
73
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070074
75def compareTimeDiffWithRoleRequest( main, term, Mode, index=0 ):
76 """
Chiyu Cheng899621b2016-11-14 11:14:48 -080077 Description:
78 Compare the time difference between the time of target term and the time of role request
79 Inclides onosclidriver functions
80
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070081 """
Chiyu Cheng899621b2016-11-14 11:14:48 -080082 try:
Devin Lim142b5342017-07-20 15:22:39 -070083 termInfo = main.Cluster.active( index ).CLI.logSearch( mode=Mode, searchTerm=term )
Chiyu Cheng899621b2016-11-14 11:14:48 -080084 termTime = getTimestampFromString( main, termInfo[ 0 ] )
85 roleRequestTime = getRoleRequestTimeFromTshark( main )
86 if termTime == -1 or roleRequestTime == -1:
87 main.writeData = -1
88 main.log.error( "Can't compare the difference with role request time" )
89 return -1
Jon Hall465d56c2016-12-05 10:03:02 -080090 # Only concern about the absolute value of difference.
Chiyu Cheng899621b2016-11-14 11:14:48 -080091 return abs( roleRequestTime - termTime )
92 except IndexError:
93 main.log.error( "Catch the wrong information of search term " )
94 main.writeData = -1
95 return -1
96
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070097
Chiyu Chengb8c2c842016-10-05 12:40:49 -070098def getInfoFromLog( main, term1, mode1, term2, mode2, index=0, funcMode='TD' ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070099 """
Chiyu Chengb8c2c842016-10-05 12:40:49 -0700100 Description:
101 Get needed informations of the search term from karaf.log
102 Includes onosclidriver functions
103 Function mode:
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700104 TD ( time difference ):
Chiyu Chengb8c2c842016-10-05 12:40:49 -0700105 Get time difference between start and end
106 Term1: startTerm
107 Term2: endTerm
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700108 DR ( disconnect rate ):
Chiyu Chengb8c2c842016-10-05 12:40:49 -0700109 Get switch disconnect rate
110 Term1: disconnectTerm
111 Term2: connectTerm
112
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700113 """
Chiyu Chengb8c2c842016-10-05 12:40:49 -0700114 try:
Devin Lim142b5342017-07-20 15:22:39 -0700115 termInfo1 = main.Cluster.active( index ).CLI.logSearch( mode=mode1, searchTerm=term1 )
116 termInfo2 = main.Cluster.active( index ).CLI.logSearch( mode=mode2, searchTerm=term2 )
Chiyu Chengb8c2c842016-10-05 12:40:49 -0700117 if funcMode == 'TD':
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700118 startTime = getTimestampFromString( main, termInfo1[ 0 ] )
119 endTime = getTimestampFromString( main, termInfo2[ 0 ] )
Chiyu Chengb8c2c842016-10-05 12:40:49 -0700120 if startTime == -1 or endTime == -1:
121 main.log.error( "Wrong Time!" )
122 main.writeData = -1
123 return -1
124 return endTime - startTime
125 if funcMode == 'DR':
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700126 # In this mode, termInfo1 means the total number of switch disconnection and
127 # termInfo2 means the total number of new switch connection
128 # termInfo2 - termInfo1 means the actual real number of switch connection.
Chiyu Chengb8c2c842016-10-05 12:40:49 -0700129 disconnection = int( termInfo1 ) * 1.0
130 expectConnection = int( main.currScale ) ** 2
131 realConnection = int( termInfo2 ) - int( termInfo1 )
132 if expectConnection != realConnection:
133 main.log.error( "The number of real switch connection doesn't match the number of expected connection" )
134 main.writeData = -1
135 return -1
136 rate = disconnection / expectConnection
137 return rate
138 except IndexError:
139 main.log.error( "Catch the wrong information of search term" )
140 main.writeData = -1
141 return -1
142
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700143
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700144def testTopology( main, topoFile='', args='', mnCmd='', timeout=300, clean=True ):
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700145 """
146 Description:
147 This function combines different wrapper functions in this module
148 to simulate a topology test
149 Test Steps:
150 - Load topology
151 - Discover topology
152 - Compare topology
153 - pingall
154 - Bring links down
155 - Compare topology
156 - pingall
157 - Bring links up
158 - Compare topology
159 - pingall
160 Options:
161 clean: Does sudo mn -c to clean mininet residue
162 Please read mininetclidriver.py >> startNet( .. ) function for details
163 Returns:
164 Returns main.TRUE if the test is successful, main.FALSE otherwise
165 """
166 testTopoResult = main.TRUE
167 compareTopoResult = main.TRUE
168 topoObjectResult = main.TRUE
169 stopResult = main.TRUE
170
171 if clean:
172 # Cleans minient
173 stopResult = stopMininet( main )
174
175 # Restart ONOS to clear hosts test new mininet topology
176 reinstallOnosResult = reinstallOnos( main )
177
178 # Starts topology
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700179 startResult = startNewTopology( main, topoFile, args, mnCmd, timeout=timeout )
GlennRC1c5df3c2015-08-27 16:12:09 -0700180 # onos needs time to see the links
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700181 time.sleep( 15 )
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700182
183 # Gets list of switches in mininet
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700184 # assignSwitch( main )
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700185
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700186 testTopoResult = startResult and topoObjectResult
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700187
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700188 return testTopoResult
189
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700190
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700191def startNewTopology( main, topoFile='', args='', mnCmd='', timeout=900 ):
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700192 """
193 Description:
194 This wrapper function starts new topology
195 Options:
196 Please read mininetclidriver.py >> startNet( .. ) function for details
197 Return:
198 Returns main.TRUE if topology is successfully created by mininet,
199 main.FALSE otherwise
200 NOTE:
201 Assumes Mininet1 is the name of the handler
202 """
203 assert main, "There is no main variable"
204 assert main.Mininet1, "Mininet 1 is not created"
205 result = main.TRUE
206
207 main.log.info( main.topoName + ": Starting new Mininet topology" )
208
209 # log which method is being used
210 if topoFile:
211 main.log.info( main.topoName + ": Starting topology with " +
212 topoFile + "topology file" )
213 elif not topoFile and not mnCmd:
214 main.log.info( main.topoName + ": Starting topology using" +
215 " the topo file" )
216 elif topoFile and mnCmd:
217 main.log.error( main.topoName + ": You can only use one " +
218 "method to start a topology" )
219 elif mnCmd:
220 main.log.info( main.topoName + ": Starting topology with '" +
221 mnCmd + "' Mininet command" )
222
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700223 result = main.Mininet1.startNet( topoFile=topoFile,
224 args=args,
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700225 mnCmd=mnCmd,
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700226 timeout=timeout )
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700227
228 return result
229
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700230
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700231def stopMininet( main ):
232 """
233 Stops current topology and execute mn -c basically triggers
234 stopNet in mininetclidrivers
235
236 NOTE: Mininet should be running when issuing this command other wise
237 the this function will cause the test to stop
238 """
239 stopResult = main.TRUE
240 stopResult = main.Mininet1.stopNet()
241 time.sleep( 30 )
242 if not stopResult:
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700243 main.log.info( main.topoName + ": Did not stop Mininet topology" )
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700244 return stopResult
245
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700246
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700247def compareTopo( main ):
248 """
249 Compare topology( devices, links, ports, hosts ) between ONOS and
250 mininet using sts
251 """
Devin Lim142b5342017-07-20 15:22:39 -0700252 try:
253 from tests.dependencies.topology import Topology
254 except ImportError:
255 main.log.error( "Topology not found exiting the test" )
Devin Lim44075962017-08-11 10:56:37 -0700256 main.cleanAndExit()
Devin Lim142b5342017-07-20 15:22:39 -0700257 try:
258 main.topoRelated
259 except ( NameError, AttributeError ):
260 main.topoRelated = Topology()
261 return main.topoRelated.compareTopos( main.Mininet1 )
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700262
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700263
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700264def assignSwitch( main ):
265 """
266 Returns switch list using getSwitch in Mininet driver
267 """
268 switchList = []
269 assignResult = main.TRUE
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700270 switchList = main.Mininet1.getSwitch()
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700271 assignResult = main.Mininet1.assignSwController( sw=switchList,
Devin Lim142b5342017-07-20 15:22:39 -0700272 ip=main.Cluster.active( 0 ).ipAddress,
GlennRC632e2892015-10-19 18:58:41 -0700273 port=6633 )
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700274
275 for sw in switchList:
276 response = main.Mininet1.getSwController( sw )
Devin Lim142b5342017-07-20 15:22:39 -0700277 if re.search( "tcp:" + main.Cluster.active( 0 ).ipAddress, response ):
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700278 assignResult = assignResult and main.TRUE
279 else:
280 assignResult = main.FALSE
281
282 return switchList
283
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700284
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700285def connectivity( main, timeout=900, shortCircuit=True, acceptableFailed=20 ):
286 """
287 Use fwd app and pingall to discover all the hosts
288 """
289 activateResult = main.TRUE
290 appCheck = main.TRUE
291 getDataResult = main.TRUE
292 main.log.info( main.topoName + ": Activating reactive forwarding app " )
Devin Lim142b5342017-07-20 15:22:39 -0700293 activateResult = main.Cluster.active( 0 ).activateApp( "org.onosproject.fwd" )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700294
295 if main.hostsData:
296 main.hostsData = {}
Devin Lim142b5342017-07-20 15:22:39 -0700297 for ctrl in main.Cluster.active():
298 appCheck = appCheck and ctrl.CLI.appToIDCheck()
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700299 if appCheck != main.TRUE:
Devin Lim142b5342017-07-20 15:22:39 -0700300 main.log.warn( ctrl.CLI.apps() )
301 main.log.warn( ctrl.CLI.appIDs() )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700302
303 time.sleep( main.fwdSleep )
304
305 # Discover hosts using pingall
306 pingResult = main.Mininet1.pingall( timeout=timeout,
307 shortCircuit=shortCircuit,
308 acceptableFailed=acceptableFailed )
309
310 main.log.info( main.topoName + ": Deactivate reactive forwarding app " )
Devin Lim142b5342017-07-20 15:22:39 -0700311 activateResult = main.Cluster.active( 0 ).deactivateApp( "org.onosproject.fwd" )
312 for ctrl in main.Cluster.active():
313 appCheck = appCheck and ctrl.CLI.appToIDCheck()
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700314 if appCheck != main.TRUE:
Devin Lim142b5342017-07-20 15:22:39 -0700315 main.log.warn( ctrl.CLI.apps() )
316 main.log.warn( ctrl.CLI.appIDs() )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700317
318 return pingResult
319
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700320
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700321def getHostsData( main ):
322 """
323 Use fwd app and pingall to discover all the hosts
324 """
325 activateResult = main.TRUE
326 appCheck = main.TRUE
327 getDataResult = main.TRUE
328 main.log.info( main.topoName + ": Activating reactive forwarding app " )
Devin Lim142b5342017-07-20 15:22:39 -0700329 activateResult = main.Cluster.active( 0 ).CLI.activateApp( "org.onosproject.fwd" )
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700330
331 if main.hostsData:
332 main.hostsData = {}
Devin Lim142b5342017-07-20 15:22:39 -0700333 for ctrl in main.Cluster.active():
334 appCheck = appCheck and ctrl.CLI.appToIDCheck()
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700335 if appCheck != main.TRUE:
Devin Lim142b5342017-07-20 15:22:39 -0700336 main.log.warn( ctrl.CLI.apps() )
337 main.log.warn( ctrl.CLI.appIDs() )
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700338
339 time.sleep( main.fwdSleep )
340 # Discover hosts using pingall
341 pingResult = main.Mininet1.pingall( timeout=900 )
342
Devin Lim142b5342017-07-20 15:22:39 -0700343 hostsJson = json.loads( main.Cluster.active( 0 ).CLI.hosts() )
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700344 hosts = main.Mininet1.getHosts().keys()
345
346 for host in hosts:
347 main.hostsData[ host ] = {}
348 main.hostsData[ host ][ 'mac' ] = \
349 main.Mininet1.getMacAddress( host ).upper()
350 for hostj in hostsJson:
351 if main.hostsData[ host ][ 'mac' ] == hostj[ 'mac' ]:
352 main.hostsData[ host ][ 'id' ] = hostj[ 'id' ]
353 main.hostsData[ host ][ 'vlan' ] = hostj[ 'vlan' ]
354 main.hostsData[ host ][ 'location' ] = \
Jeremy Ronquillo0e538bc2017-06-13 15:16:09 -0700355 hostj[ 'locations' ][ 0 ][ 'elementId' ] + '/' + \
356 hostj[ 'locations' ][ 0 ][ 'port' ]
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700357 main.hostsData[ host ][ 'ipAddresses' ] = hostj[ 'ipAddresses' ]
358
359 if activateResult and main.hostsData:
360 main.log.info( main.topoName + ": Successfully used fwd app" +
361 " to discover hosts " )
362 getDataResult = main.TRUE
363 else:
364 main.log.info( main.topoName + ": Failed to use fwd app" +
365 " to discover hosts " )
366 getDataResult = main.FALSE
367
368 main.log.info( main.topoName + ": Deactivate reactive forwarding app " )
Devin Lim142b5342017-07-20 15:22:39 -0700369 activateResult = main.Cluster.active( 0 ).CLI.deactivateApp( "org.onosproject.fwd" )
370 for ctrl in main.Cluster.active():
371 appCheck = appCheck and ctrl.CLI.appToIDCheck()
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700372 if appCheck != main.TRUE:
Devin Lim142b5342017-07-20 15:22:39 -0700373 main.log.warn( ctrl.CLI.apps() )
374 main.log.warn( ctrl.CLI.appIDs() )
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700375
376 # This data can be use later for intents
377 print main.hostsData
378
379 return getDataResult
380
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700381
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700382def reinstallOnos( main ):
383 """
384 Description:
385 Stop and start ONOS that clears hosts,devices etc. in order to test
386 new mininet topology
387 Return:
388 Retruns main.TRUE for a successful restart, main.FALSE otherwise.
389 """
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700390 stopResult = []
391 startResult = []
392 onosIsUpResult = []
393 restartResult = main.TRUE
394
Devin Lim142b5342017-07-20 15:22:39 -0700395 uninstallResult = main.testSetUp.uninstallOnos( main.Cluster, False )
396 if uninstallResult != main.TRUE:
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700397 restartResult = main.FALSE
Devin Lim142b5342017-07-20 15:22:39 -0700398 installResult = main.testSetUp.installOnos( main.Cluster, False )
399 if installResult != main.TRUE:
You Wangf5de25b2017-01-06 15:13:01 -0800400 restartResult = main.FALSE
401
Devin Lim142b5342017-07-20 15:22:39 -0700402 secureSshResult = main.testSetUp.setupSsh( main.Cluster )
403 if secureSshResult != main.TRUE:
404 restartResult = main.FALSE
405
406 for ctrl in main.Cluster.runningNodes:
407 onosIsUpResult.append( main.ONOSbench.isup( ctrl.ipAddress ) )
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700408
409 if all( result == main.TRUE for result in onosIsUpResult ):
410 main.log.report( "ONOS instance is up and ready" )
411 else:
412 main.log.report( "ONOS instance may not be up, stop and " +
413 "start ONOS again " )
Devin Lim142b5342017-07-20 15:22:39 -0700414 for ctrl in main.Cluster.runningNodes:
415 stopResult.append( main.ONOSbench.onosStop( ctrl.ipAddress ) )
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700416
417 if all( result == main.TRUE for result in stopResult ):
418 main.log.info( main.topoName + ": Successfully stop ONOS cluster" )
419 else:
420 main.log.error( main.topoName + ": Failed to stop ONOS cluster" )
421
Devin Lim142b5342017-07-20 15:22:39 -0700422 for ctrl in main.Cluster.runningNodes:
423 startResult.append( main.ONOSbench.onosStart( ctrl.ipAddress ) )
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700424
425 if all( result == main.TRUE for result in startResult ):
426 main.log.info( main.topoName + ": Successfully start ONOS cluster" )
427 else:
428 main.log.error( main.topoName + ": Failed to start ONOS cluster" )
429
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700430 main.log.info( main.topoName + ": Starting ONOS CLI" )
Devin Lim142b5342017-07-20 15:22:39 -0700431 cliResult = main.testSetUp.startOnosClis( main.Cluster )
432 if cliResult != main.TRUE:
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700433 restartResult = main.FALSE
434
kelvin-onlab1d381fe2015-07-14 16:24:56 -0700435 return restartResult