blob: 78be8ace9bda1f66b4dabfc75c7bc54c418b0196 [file] [log] [blame]
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -07001"""
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"""
Jon Hall1efcb3f2016-08-23 13:42:15 -070021import os
Jon Hall1efcb3f2016-08-23 13:42:15 -070022import time
23import json
24import urllib
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -070025import re
Jon Hallf6aeda22020-07-28 09:12:56 -070026import pexpect
Jon Hall1efcb3f2016-08-23 13:42:15 -070027from core import utilities
28
29
30class Testcaselib:
Pierfb719b12016-09-19 14:51:44 -070031
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070032 useSSH = True
Pierfb719b12016-09-19 14:51:44 -070033
Jon Hall1efcb3f2016-08-23 13:42:15 -070034 @staticmethod
35 def initTest( main ):
36 """
37 - Construct tests variables
38 - GIT ( optional )
39 - Checkout ONOS master branch
40 - Pull latest ONOS code
41 - Building ONOS ( optional )
42 - Install ONOS package
43 - Build ONOS package
44 """
Devin Lim58046fa2017-07-05 16:55:00 -070045 try:
46 from tests.dependencies.ONOSSetup import ONOSSetup
47 main.testSetUp = ONOSSetup()
48 except ImportError:
49 main.log.error( "ONOSSetup not found. exiting the test" )
Devin Lim44075962017-08-11 10:56:37 -070050 main.cleanAndExit()
You Wangd5873482018-01-24 12:30:00 -080051 from tests.dependencies.Network import Network
Jon Hall627b1572020-12-01 12:01:15 -080052 main.persistentSetup = main.params.get( "persistent_setup" )
You Wangd5873482018-01-24 12:30:00 -080053 main.Network = Network()
Jon Hall43060f62020-06-23 13:13:33 -070054 main.physicalNet = False
Devin Lim0c972b72018-02-08 14:53:59 -080055 main.testSetUp.envSetupDescription( False )
Jon Hall39570262020-11-17 12:18:19 -080056 main.logdirBase = main.logdir
Devin Lim58046fa2017-07-05 16:55:00 -070057 stepResult = main.FALSE
58 try:
Devin Lim58046fa2017-07-05 16:55:00 -070059 # Test variables
60 main.cellName = main.params[ 'ENV' ][ 'cellName' ]
61 main.apps = main.params[ 'ENV' ][ 'cellApps' ]
Devin Lim58046fa2017-07-05 16:55:00 -070062 main.path = os.path.dirname( main.testFile )
Devin Lim57221b02018-02-14 15:45:36 -080063 main.useCommonTopo = main.params[ 'DEPENDENCY' ][ 'useCommonTopo' ] == 'True'
64 main.topoPath = main.path + ( "/.." if main.useCommonTopo else "" ) + "/dependencies/"
65 main.useCommonConf = main.params[ 'DEPENDENCY' ][ 'useCommonConf' ] == 'True'
You Wang68568b12019-03-04 11:49:57 -080066 if main.params[ 'DEPENDENCY' ].get( 'useBmv2' ):
67 main.useBmv2 = main.params[ 'DEPENDENCY' ][ 'useBmv2' ] == 'True'
68 else:
69 main.useBmv2 = False
Jon Hall43060f62020-06-23 13:13:33 -070070 if main.useBmv2:
71 main.switchType = main.params[ 'DEPENDENCY' ].get( 'bmv2SwitchType', 'stratum' )
72 else:
73 main.switchType = "ovs"
74
Devin Lim57221b02018-02-14 15:45:36 -080075 main.configPath = main.path + ( "/.." if main.useCommonConf else "" ) + "/dependencies/"
Jon Hallbc1c1c92020-05-27 09:29:30 -070076 main.bmv2Path = "/tools/dev/mininet/"
Devin Lim57221b02018-02-14 15:45:36 -080077 main.forJson = "json/"
Siddesh606bd872021-06-29 23:42:36 +000078 main.forcfg = "netcfg/"
Devin Lim57221b02018-02-14 15:45:36 -080079 main.forChart = "chart/"
80 main.forConfig = "conf/"
81 main.forHost = "host/"
You Wang27317572018-03-06 12:13:11 -080082 main.forSwitchFailure = "switchFailure/"
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -080083 main.forLinkFailure = "linkFailure/"
You Wange24d6272018-03-27 21:18:50 -070084 main.forMulticast = "multicast/"
Devin Lim58046fa2017-07-05 16:55:00 -070085 main.topology = main.params[ 'DEPENDENCY' ][ 'topology' ]
You Wangd87b2312018-01-30 12:47:17 -080086 main.topologyLib = main.params[ 'DEPENDENCY' ][ 'lib' ] if 'lib' in main.params[ 'DEPENDENCY' ] else None
87 main.topologyConf = main.params[ 'DEPENDENCY' ][ 'conf' ] if 'conf' in main.params[ 'DEPENDENCY' ] else None
You Wang68568b12019-03-04 11:49:57 -080088 main.bmv2 = "bmv2.py"
Jon Halldac3eae2020-06-05 12:04:06 -070089 main.stratumRoot = main.params[ 'DEPENDENCY'][ 'stratumRoot'] if 'stratumRoot' in main.params[ 'DEPENDENCY' ] else None
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070090 main.scale = ( main.params[ 'SCALE' ][ 'size' ] ).split( "," )
Devin Lim58046fa2017-07-05 16:55:00 -070091 main.maxNodes = int( main.params[ 'SCALE' ][ 'max' ] )
Jon Hall3c0114c2020-08-11 15:07:42 -070092 main.trellisOar = main.params[ 'DEPENDENCY' ][ 'trellisOar' ] if 'trellisOar' in main.params[ 'DEPENDENCY' ] else None
You Wang5bf49592020-07-08 18:47:46 -070093 main.t3Oar = main.params[ 'DEPENDENCY' ][ 't3Oar' ] if 't3Oar' in main.params[ 'DEPENDENCY' ] else None
Jon Hall1efcb3f2016-08-23 13:42:15 -070094
Devin Lim0c972b72018-02-08 14:53:59 -080095 stepResult = main.testSetUp.envSetup( False )
Devin Lim58046fa2017-07-05 16:55:00 -070096 except Exception as e:
97 main.testSetUp.envSetupException( e )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -070098
Jon Hallaa1d9b82020-07-30 13:49:42 -070099 main.testSetUp.envSetupConclusion( stepResult )
Jon Hall32c90f32021-06-24 16:32:44 -0700100
Siddesh167bc882021-03-23 21:03:43 +0000101 @staticmethod
102 def getTopo():
103 topo = dict()
104 # TODO: Check minFlowCount of leaf for BMv2 switch
105 # (number of spine switch, number of leaf switch, dual-homed, description, minFlowCount - leaf (OvS), minFlowCount - leaf (BMv2))
106 topo[ '0x1' ] = { 'spines': 0,'leaves': 1, 'mininetArgs': "--leaf=1 --spine=0", 'dual-homed': False,'description': 'single ToR','minFlow-OvS': 28,'minFlow-Stratum': 20,'dual-linked': False }
107 topo[ '0x2' ] = {'spines': 0,'leaves': 2, 'mininetArgs': "--leaf=2 --spine=0", 'dual-homed': True,'description': 'dual-homed ToR','minFlow-OvS': 37,'minFlow-Stratum': 37,'dual-linked': True }
108 topo[ '2x2' ] = {'spines': 2,'leaves': 2, 'mininetArgs': "--leaf=2 --spine=2", 'dual-homed': False,'description': '2x2 leaf-spine topology','minFlow-OvS': 37,'minFlow-Stratum': 32,'dual-linked': False }
109 topo[ '2x2 dual-linked' ] = {'spines': 2, 'leaves': 2, 'mininetArgs': "--leaf=2 --spine=2", 'dual-homed': False,'description': '2x2 aether dual-linked','minFlow-OvS': 37,'minFlow-Stratum': 32,'dual-linked': True }
110 topo[ '2x4' ] = { 'spines':2,'leaves': 4, 'mininetArgs': "--leaf=4 --spine=2",'dual-homed': True,'description': '2x4 dual-homed leaf-spine topology','minFlow-OvS': 53,'minFlow-Stratum': 53, 'dual-linked': False }
111 topo[ '4x4' ] = {'spines': 4,'leaves': 4, 'dual-homed': True, 'description': '4x4 dual-homed leaf-spine topology','dual-linked': True }
112 topo[ '2x2staging' ] = { 'spines': 2, 'leaves': 2,'dual-homed': True, 'description': '2x2 leaf-spine topology', 'minFlowOvS': 37, 'minFlow-Stratum': 32 }
113 return topo
Jon Hall1efcb3f2016-08-23 13:42:15 -0700114 @staticmethod
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800115 def installOnos( main, vlanCfg=True, skipPackage=False, cliSleep=10,
116 parallel=True ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700117 """
118 - Set up cell
119 - Create cell file
120 - Set cell file
121 - Verify cell file
122 - Kill ONOS process
123 - Uninstall ONOS cluster
124 - Verify ONOS start up
125 - Install ONOS cluster
126 - Connect to cli
127 """
Siddesh13492972021-03-12 21:09:32 +0000128 # Check params file for local repos on external apps. cd to repos, run the build command, potentially move o/p file to a different location
129
Jon Hall1efcb3f2016-08-23 13:42:15 -0700130 # main.scale[ 0 ] determines the current number of ONOS controller
Jon Hall43060f62020-06-23 13:13:33 -0700131 try:
Jon Hall627b1572020-12-01 12:01:15 -0800132 if not main.persistentSetup and main.params.get( 'EXTERNAL_APPS' ):
Jon Hall43060f62020-06-23 13:13:33 -0700133 for app, url in main.params[ 'EXTERNAL_APPS' ].iteritems():
Jon Hall39570262020-11-17 12:18:19 -0800134 main.log.info( "Downloading %s app from %s" % ( app, url ) )
Jon Hall43060f62020-06-23 13:13:33 -0700135 main.ONOSbench.onosFetchApp( url )
136 if not main.apps:
137 main.log.error( "App list is empty" )
138 except Exception as e:
139 main.log.debug( e )
140 main.cleanAndExit()
Jon Hall3c910162018-03-07 14:42:16 -0800141 main.log.info( "Cluster size: " + str( main.Cluster.numCtrls ) )
142 main.log.info( "Cluster ips: " + ', '.join( main.Cluster.getIps() ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700143 main.dynamicHosts = [ 'in1', 'out1' ]
You Wanga0f6ff62018-01-11 15:46:30 -0800144 main.testSetUp.ONOSSetUp( main.Cluster, newCell=True, cellName=main.cellName,
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800145 skipPack=skipPackage,
146 useSSH=Testcaselib.useSSH,
Devin Lim0c972b72018-02-08 14:53:59 -0800147 installParallel=parallel, includeCaseDesc=False )
Devin Lim142b5342017-07-20 15:22:39 -0700148 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -0700149 [ None, main.FALSE ],
You Wang1cdc5f52017-12-19 16:47:51 -0800150 sleep=cliSleep,
Devin Lim142b5342017-07-20 15:22:39 -0700151 attempts=10 )
152 if ready:
153 ready = main.TRUE
154 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700155 onpass="ONOS summary command succeded",
156 onfail="ONOS summary command failed" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700157 if not ready:
158 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700159 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700160
You Wang5bf49592020-07-08 18:47:46 -0700161 # Install segmentrouting and t3 app
Jon Hall3c0114c2020-08-11 15:07:42 -0700162 appInstallResult = main.TRUE
163 if main.trellisOar:
164 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.trellisOar)
You Wang5bf49592020-07-08 18:47:46 -0700165 if main.t3Oar:
166 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.t3Oar)
167 utilities.assert_equals( expect=main.TRUE, actual=appInstallResult,
168 onpass="SR app installation succeded",
169 onfail="SR app installation failed" )
170 if not appInstallResult:
171 main.cleanAndExit()
172
Jon Hall43060f62020-06-23 13:13:33 -0700173 # FIXME: move to somewhere else?
174 switchPrefix = main.params[ 'DEPENDENCY' ].get( 'switchPrefix' )
175 # TODO: Support other pipeconfs/making this configurable
176 if switchPrefix == "tofino":
177 # It seems to take some time for the pipeconfs to be loaded
178 ctrl = main.Cluster.next()
179 for i in range( 120 ):
180 try:
181 main.log.debug( "Checking to see if pipeconfs are loaded" )
182 output = ctrl.CLI.sendline( "pipeconfs" )
183 if "tofino" in output:
184 main.log.debug( "Took around %s seconds for the pipeconf to be loaded" % i )
185 break
186 time.sleep( 1 )
187 except Exception as e:
188 main.log.error( e )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700189
Jon Hall627b1572020-12-01 12:01:15 -0800190 # Install segmentrouting and t3 app
191 appInstallResult = main.TRUE
192 if not main.persistentSetup:
193 if main.trellisOar:
194 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.trellisOar)
195 if main.t3Oar:
196 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.t3Oar)
197 utilities.assert_equals( expect=main.TRUE, actual=appInstallResult,
198 onpass="SR app installation succeded",
199 onfail="SR app installation failed" )
200 if not appInstallResult:
201 main.cleanAndExit()
202
Jon Hall43060f62020-06-23 13:13:33 -0700203 Testcaselib.setOnosLogLevels( main )
204 Testcaselib.setOnosConfig( main )
Jon Halldac3eae2020-06-05 12:04:06 -0700205
Jon Hall1efcb3f2016-08-23 13:42:15 -0700206 @staticmethod
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800207 def loadCount( main ):
Jon Hall43060f62020-06-23 13:13:33 -0700208 with open( "%s/count/%s.count" % ( main.configPath, main.cfgName ) ) as count:
209 main.count = json.load( count )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800210
211 @staticmethod
Jon Hall43060f62020-06-23 13:13:33 -0700212 def loadJson( main, suffix='' ):
213 with open( "%s%s.json%s" % ( main.configPath + main.forJson,
214 main.cfgName, suffix ) ) as cfg:
Devin Lim57221b02018-02-14 15:45:36 -0800215 main.Cluster.active( 0 ).REST.setNetCfg( json.load( cfg ) )
216
217 @staticmethod
Siddesh606bd872021-06-29 23:42:36 +0000218 def loadNewJson( main, suffix='' ):
219 returnValue = main.TRUE
220 with open( "%s%s.cfg%s" % ( main.configPath + main.forcfg,
221 main.cfgName, suffix ) ) as cfg:
222 desiredJSON = json.load ( cfg )
223 for device in desiredJSON ["ports"].keys():
224 deviceCfg = desiredJSON[ "ports" ][ device ]
225 currentJSON = main.Cluster.active( 0 ).REST.getNetCfg( subjectClass = "ports", subjectKey = device )
226
227 currentJSON = json.loads( currentJSON )
228 if currentJSON['interfaces'][0]['ips'] != deviceCfg['interfaces'][0]['ips']:
Siddeshd9840842021-08-06 19:26:05 +0000229 currentJSON['interfaces'][0]['ips'] = deviceCfg['interfaces'][0]['ips']
Siddesh606bd872021-06-29 23:42:36 +0000230 data = { 'interfaces': currentJSON['interfaces'] }
231 A = main.Cluster.active( 0 ).REST.setNetCfg( data , subjectClass = "ports", subjectKey = device )
232 returnValue = returnValue and A
233 currentJSON['interfaces'] = deviceCfg['interfaces']
234 data = { 'interfaces': currentJSON['interfaces'] }
235 B = main.Cluster.active( 0 ).REST.setNetCfg( data , subjectClass = "ports", subjectKey = device )
236 returnValue = returnValue and B
237 return returnValue
238
239 @staticmethod
Jon Hall10e2ab82020-09-15 17:14:54 -0700240 def loadXconnects( main, suffix='' ):
241 with open( "%s%s-xconnects.json%s" % ( main.configPath + main.forJson,
242 main.cfgName, suffix ) ) as cfg:
243 for xconnect in json.load( cfg ).get('xconnects'):
244 main.Cluster.active( 0 ).REST.setXconnectJson( xconnect )
245
246 @staticmethod
Devin Lim57221b02018-02-14 15:45:36 -0800247 def loadChart( main ):
248 try:
Jon Hall32c90f32021-06-24 16:32:44 -0700249 filename = "%s%s.chart" % ( main.configPath + main.forChart,
250 main.cfgName )
251 with open( filename ) as chart:
Jon Hall43060f62020-06-23 13:13:33 -0700252 main.pingChart = json.load( chart )
Devin Lim57221b02018-02-14 15:45:36 -0800253 except IOError:
Jon Hall32c90f32021-06-24 16:32:44 -0700254 main.log.warn( "No chart file found at %s" % filename )
Devin Lim57221b02018-02-14 15:45:36 -0800255
256 @staticmethod
257 def loadHost( main ):
258 with open( "%s%s.host" % ( main.configPath + main.forHost,
259 main.cfgName ) ) as host:
260 main.expectedHosts = json.load( host )
261
262 @staticmethod
You Wang27317572018-03-06 12:13:11 -0800263 def loadSwitchFailureChart( main ):
264 with open( "%s%s.switchFailureChart" % ( main.configPath + main.forSwitchFailure,
265 main.cfgName ) ) as sfc:
266 main.switchFailureChart = json.load( sfc )
267
268 @staticmethod
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800269 def loadLinkFailureChart( main ):
270 with open( "%s%s.linkFailureChart" % ( main.configPath + main.forLinkFailure,
You Wange24d6272018-03-27 21:18:50 -0700271 main.cfgName ) ) as lfc:
272 main.linkFailureChart = json.load( lfc )
273
274 @staticmethod
275 def loadMulticastConfig( main ):
276 with open( "%s%s.multicastConfig" % ( main.configPath + main.forMulticast,
277 main.cfgName ) ) as cfg:
278 main.multicastConfig = json.load( cfg )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800279
280 @staticmethod
Jon Hall1efcb3f2016-08-23 13:42:15 -0700281 def startMininet( main, topology, args="" ):
Jon Hall43060f62020-06-23 13:13:33 -0700282 main.log.info( "Copying mininet topology file to mininet machine" )
You Wangd87b2312018-01-30 12:47:17 -0800283 copyResult = main.ONOSbench.scp( main.Mininet1,
284 main.topoPath + main.topology,
You Wang5da39c82018-04-26 22:55:08 -0700285 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800286 direction="to" )
287 if main.topologyLib:
288 for lib in main.topologyLib.split(","):
289 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
290 main.topoPath + lib,
You Wang5da39c82018-04-26 22:55:08 -0700291 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800292 direction="to" )
293 if main.topologyConf:
You Wanga877ea42018-04-05 15:27:40 -0700294 import re
295 controllerIPs = [ ctrl.ipAddress for ctrl in main.Cluster.runningNodes ]
296 index = 0
Jon Hall43060f62020-06-23 13:13:33 -0700297 destDir = "~/"
298 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
299 destDir = "/tmp/mn_conf/"
300 # Try to ensure the destination exists
You Wangd87b2312018-01-30 12:47:17 -0800301 for conf in main.topologyConf.split(","):
You Wanga877ea42018-04-05 15:27:40 -0700302 # Update zebra configurations with correct ONOS instance IP
303 if conf in [ "zebradbgp1.conf", "zebradbgp2.conf" ]:
304 ip = controllerIPs[ index ]
305 index = ( index + 1 ) % len( controllerIPs )
306 with open( main.configPath + main.forConfig + conf ) as f:
307 s = f.read()
308 s = re.sub( r"(fpm connection ip).*(port 2620)", r"\1 " + ip + r" \2", s )
309 with open( main.configPath + main.forConfig + conf, "w" ) as f:
310 f.write( s )
You Wangd87b2312018-01-30 12:47:17 -0800311 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Devin Lim57221b02018-02-14 15:45:36 -0800312 main.configPath + main.forConfig + conf,
Jon Hall43060f62020-06-23 13:13:33 -0700313 destDir,
You Wangd87b2312018-01-30 12:47:17 -0800314 direction="to" )
You Wang68568b12019-03-04 11:49:57 -0800315 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Jon Hallbc1c1c92020-05-27 09:29:30 -0700316 main.ONOSbench.home + main.bmv2Path + main.bmv2,
You Wang68568b12019-03-04 11:49:57 -0800317 main.Mininet1.home + "custom",
318 direction="to" )
Jon Hall9b0de1f2020-08-24 15:38:04 -0700319
320 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
321 # move the config files into home
322 main.Mininet1.handle.sendline( "cp config/* . " )
323 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
324 main.log.debug( main.Mininet1.handle.before + main.Mininet1.handle.after )
325 main.Mininet1.handle.sendline( "ls -al " )
326 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
327 main.log.debug( main.Mininet1.handle.before + main.Mininet1.handle.after )
328
You Wangd87b2312018-01-30 12:47:17 -0800329 stepResult = copyResult
330 utilities.assert_equals( expect=main.TRUE,
331 actual=stepResult,
332 onpass="Successfully copied topo files",
333 onfail="Failed to copy topo files" )
Jon Halldac3eae2020-06-05 12:04:06 -0700334 if main.stratumRoot:
335 main.Mininet1.handle.sendline( "export STRATUM_ROOT=" + str( main.stratumRoot ) )
Jon Hall3c0114c2020-08-11 15:07:42 -0700336 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700337 main.step( "Starting Mininet Topology" )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700338 arg = "--onos-ip=%s %s" % (",".join([ctrl.ipAddress for ctrl in main.Cluster.runningNodes]), args)
Jon Hall1efcb3f2016-08-23 13:42:15 -0700339 main.topology = topology
340 topoResult = main.Mininet1.startNet(
You Wang5da39c82018-04-26 22:55:08 -0700341 topoFile=main.Mininet1.home + "custom/" + main.topology, args=arg )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700342 stepResult = topoResult
343 utilities.assert_equals( expect=main.TRUE,
344 actual=stepResult,
345 onpass="Successfully loaded topology",
346 onfail="Failed to load topology" )
347 # Exit if topology did not load properly
348 if not topoResult:
Devin Lim44075962017-08-11 10:56:37 -0700349 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700350 if main.useBmv2:
Jon Hall3c0114c2020-08-11 15:07:42 -0700351 main.step( "Configure switches in ONOS" )
Jon Hall43060f62020-06-23 13:13:33 -0700352 # Upload the net-cfg file created for each switch
353 filename = "onos-netcfg.json"
354 switchPrefix = main.params[ 'DEPENDENCY' ].get( 'switchPrefix', "bmv2" )
Jon Hall3c0114c2020-08-11 15:07:42 -0700355 switchNetCfg = main.TRUE
Jon Hall43060f62020-06-23 13:13:33 -0700356 for switch in main.Mininet1.getSwitches( switchRegex=r"(StratumBmv2Switch)|(Bmv2Switch)" ).keys():
357 path = "/tmp/mn-stratum/%s/" % switch
358 dstPath = "/tmp/"
359 dstFileName = "%s-onos-netcfg.json" % switch
360 main.ONOSbench1.scp( main.Mininet1,
361 "%s%s" % ( path, filename ),
362 "%s%s" % ( dstPath, dstFileName ),
363 "from" )
364 main.ONOSbench1.handle.sendline( "sudo sed -i 's/localhost/%s/g' %s%s" % ( main.Mininet1.ip_address, dstPath, dstFileName ) )
Jon Hall3c0114c2020-08-11 15:07:42 -0700365 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
Jon Hall43060f62020-06-23 13:13:33 -0700366 # Configure managementAddress
367 main.ONOSbench1.handle.sendline( "sudo sed -i 's/localhost/%s/g' %s%s" % ( main.Mininet1.ip_address, dstPath, dstFileName ) )
368 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
369 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
370 # Configure device id
371 main.ONOSbench1.handle.sendline( "sudo sed -i 's/device:%s/device:%s:%s/g' %s%s" % ( switch, switchPrefix, switch, dstPath, dstFileName ) )
372 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
373 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
374 # Configure device name
Jon Hall39570262020-11-17 12:18:19 -0800375 main.ONOSbench1.handle.sendline( "sudo sed -i '/\"basic\"/a\ \"name\": \"%s:%s\",' %s%s" % ( switchPrefix, switch, dstPath, dstFileName ) )
Jon Hall43060f62020-06-23 13:13:33 -0700376 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
377 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
Jon Hall3c0114c2020-08-11 15:07:42 -0700378 node = main.Cluster.active(0)
379 switchNetCfg = switchNetCfg and node.onosNetCfg( node.server.ip_address,
380 dstPath,
381 dstFileName,
382 user=node.REST.user_name,
383 password=node.REST.pwd )
384 # Stop test if we fail to push switch netcfg
385 utilities.assert_equals( expect=main.TRUE,
386 actual=switchNetCfg,
387 onpass="Successfully pushed switch netcfg",
388 onfail="Failed to configure switches in onos" )
389 if not switchNetCfg:
390 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700391 # Make sure hosts make some noise
392 Testcaselib.discoverHosts( main )
393
394 @staticmethod
395 def discoverHosts( main ):
396 # TODO add option to only select specific hosts
397 if hasattr( main, "Mininet1" ):
398 network = main.Mininet1
399 elif hasattr( main, "NetworkBench" ):
400 network = main.NetworkBench
401 else:
402 main.log.warn( "Could not find component for test network, skipping host discovery" )
403 return
404 network.discoverHosts()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700405
406 @staticmethod
Jon Hall06fd0df2021-01-25 15:50:06 -0800407 def connectToPhysicalNetwork( main, hostDiscovery=True ):
You Wang84f981d2018-01-12 16:11:50 -0800408 main.step( "Connecting to physical netowrk" )
Jon Hall43060f62020-06-23 13:13:33 -0700409 main.physicalNet = True
You Wang84f981d2018-01-12 16:11:50 -0800410 topoResult = main.NetworkBench.connectToNet()
411 stepResult = topoResult
412 utilities.assert_equals( expect=main.TRUE,
413 actual=stepResult,
Jon Hall43060f62020-06-23 13:13:33 -0700414 onpass="Successfully connected to topology",
415 onfail="Failed to connect to topology" )
You Wang84f981d2018-01-12 16:11:50 -0800416 # Exit if topology did not load properly
417 if not topoResult:
418 main.cleanAndExit()
419
Jon Hall627b1572020-12-01 12:01:15 -0800420 if not main.persistentSetup:
421 # Perform any optional setup
422 for switch in main.NetworkBench.switches:
423 if hasattr( switch, "setup" ):
424 switch.setup() # We might not need this
Jon Hall43060f62020-06-23 13:13:33 -0700425
Jon Hall627b1572020-12-01 12:01:15 -0800426 main.step( "Assign switches to controllers." )
427 stepResult = main.TRUE
428 switches = main.NetworkBench.getSwitches()
429 pool = []
430 for name in switches.keys():
431 # NOTE: although this terminology is ovsdb centric, we can use this function for other switches too
432 # e.g. push onos net-cfg for stratum switches
433 thread = main.Thread( target=main.NetworkBench.assignSwController,
434 name="assignSwitchToController",
435 args=[ name, main.Cluster.getIps(), '6653' ] )
436 pool.append( thread )
437 thread.start()
438 for thread in pool:
439 thread.join( 300 )
440 if not thread.result:
441 stepResult = main.FALSE
442 utilities.assert_equals( expect=main.TRUE,
443 actual=stepResult,
444 onpass="Successfully assign switches to controllers",
445 onfail="Failed to assign switches to controllers" )
You Wang84f981d2018-01-12 16:11:50 -0800446
You Wang4cc61912018-08-28 10:10:58 -0700447 # Check devices
448 Testcaselib.checkDevices( main, switches=int( main.params[ 'TOPO' ][ 'switchNum' ] ) )
You Wang4cc61912018-08-28 10:10:58 -0700449 # Connecting to hosts that only have data plane connectivity
450 main.step( "Connecting inband hosts" )
451 stepResult = main.Network.connectInbandHosts()
452 utilities.assert_equals( expect=main.TRUE,
453 actual=stepResult,
454 onpass="Successfully connected inband hosts",
455 onfail="Failed to connect inband hosts" )
Jon Hall06fd0df2021-01-25 15:50:06 -0800456 if hostDiscovery:
457 Testcaselib.discoverHosts( main )
You Wang4cc61912018-08-28 10:10:58 -0700458
You Wang84f981d2018-01-12 16:11:50 -0800459 @staticmethod
You Wang5df1c6d2018-04-06 18:02:02 -0700460 def saveOnosDiagnostics( main ):
461 """
462 Get onos-diags.tar.gz and save it to the log directory.
463 suffix: suffix string of the file name. E.g. onos-diags-case1.tar.gz
464 """
465 main.log.info( "Collecting onos-diags..." )
Siddesha2938fe2021-04-06 02:46:06 +0000466 for ctrl in main.Cluster.runningNodes:
467 main.ONOSbench.onosDiagnostics( [ctrl.ipAddress], main.logdir,"-CASE%d" % main.CurrentTestCaseNumber, onosPortnumber=ctrl.REST.port )
You Wang5df1c6d2018-04-06 18:02:02 -0700468
469 @staticmethod
Devin Lim142b5342017-07-20 15:22:39 -0700470 def config( main, cfgName ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700471 main.spines = []
Piera2a7e1b2016-10-04 11:51:43 -0700472
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700473 main.failures = int( main.params[ 'failures' ] )
474 main.cfgName = cfgName
Piera2a7e1b2016-10-04 11:51:43 -0700475
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700476 if main.cfgName == '2x2':
477 spine = {}
478 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
479 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
480 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700481
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700482 spine = {}
483 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
484 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
485 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700486
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700487 elif main.cfgName == '4x4':
488 spine = {}
489 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
490 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
491 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700492
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700493 spine = {}
494 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
495 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
496 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700497
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700498 spine = {}
499 spine[ 'name' ] = main.params[ 'switches' ][ 'spine3' ]
500 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid3' ]
501 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700502
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700503 spine = {}
504 spine[ 'name' ] = main.params[ 'switches' ][ 'spine4' ]
505 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid4' ]
506 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700507
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700508 else:
Piera2a7e1b2016-10-04 11:51:43 -0700509 main.log.error( "Configuration failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700510 main.cleanAndExit()
You Wang27317572018-03-06 12:13:11 -0800511
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800512 @staticmethod
513 def addStaticOnosRoute( main, subnet, intf):
514 """
515 Adds an ONOS static route with the use route-add command.
516 """
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800517 routeResult = main.Cluster.active( 0 ).addStaticRoute(subnet, intf)
518
Piera2a7e1b2016-10-04 11:51:43 -0700519 @staticmethod
You Wangc02f3be2018-05-18 12:14:23 -0700520 def checkGroupsForBuckets( main, deviceId, subnetDict, routingTable=30 ):
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700521 """
522 Check number of groups for each subnet on device deviceId and matches
523 it with an expected value. subnetDict is a dictionarty containing values
524 of the type "10.0.1.0/24" : 5.
525 """
You Wangc02f3be2018-05-18 12:14:23 -0700526 main.step( "Checking if number of groups for subnets in device {0} is as expected.".format( deviceId ) )
527 groups = main.Cluster.active( 0 ).CLI.getGroups( deviceId, groupType="select" )
528 flows = main.Cluster.active( 0 ).CLI.flows( jsonFormat=False, device=deviceId )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700529
You Wangc02f3be2018-05-18 12:14:23 -0700530 result = main.TRUE
531 for subnet, numberInSelect in subnetDict.iteritems():
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700532 for flow in flows.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700533 if "tableId={0}".format( routingTable ) in flow and subnet in flow:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700534 # this will match the group id that this flow entry points to, for example :
535 # 0x70000041 in flow entry which contains "deferred=[GROUP:0x70000041], transition=TABLE:60,"
You Wangc02f3be2018-05-18 12:14:23 -0700536 groupId = re.search( r".*GROUP:(0x.*)], transition.*", flow ).groups()[0]
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700537 count = 0
538 for group in groups.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700539 if 'id={0}'.format( groupId ) in group:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700540 count += 1
You Wangc02f3be2018-05-18 12:14:23 -0700541 if count - 1 != numberInSelect:
542 result = main.FALSE
543 main.log.warn( "Mismatch in number of buckets of select group, found {0}, expected {1} for subnet {2} on device {3}".format( count - 1, numberInSelect, subnet, deviceId ) )
544 utilities.assert_equals( expect=main.TRUE, actual=result,
545 onpass="All bucket numbers are as expected",
546 onfail="Some bucket numbers are not as expected" )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700547
548 @staticmethod
Jon Hall32c90f32021-06-24 16:32:44 -0700549 def checkFlows( main, minFlowCount, tag="", dumpFlows=True, sleep=10 ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700550 main.step(
Jon Hall39570262020-11-17 12:18:19 -0800551 "Check whether the flow count is >= %s" % minFlowCount )
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900552 if tag == "":
553 tag = 'CASE%d' % main.CurrentTestCaseNumber
Devin Lim142b5342017-07-20 15:22:39 -0700554 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowCount,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700555 main.FALSE,
556 kwargs={ 'min': minFlowCount },
557 attempts=10,
You Wang1cdc5f52017-12-19 16:47:51 -0800558 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800559 if count == main.FALSE:
560 count = main.Cluster.active( 0 ).CLI.checkFlowCount()
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700561 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700562 expect=True,
Jon Hall39570262020-11-17 12:18:19 -0800563 actual=( count >= minFlowCount ),
Jon Hall43060f62020-06-23 13:13:33 -0700564 onpass="Flow count looks correct; found %s, expecting at least %s" % ( count, minFlowCount ),
565 onfail="Flow count looks wrong; found %s, expecting at least %s" % ( count, minFlowCount ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700566
567 main.step( "Check whether all flow status are ADDED" )
Devin Lim142b5342017-07-20 15:22:39 -0700568 flowCheck = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowsState,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700569 main.FALSE,
570 kwargs={ 'isPENDING': False },
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800571 attempts=5,
You Wang1cdc5f52017-12-19 16:47:51 -0800572 sleep=sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700573 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700574 expect=main.TRUE,
575 actual=flowCheck,
576 onpass="Flow status is correct!",
577 onfail="Flow status is wrong!" )
Jon Hall32c90f32021-06-24 16:32:44 -0700578 if dumpFlows:
Devin Lim142b5342017-07-20 15:22:39 -0700579 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700580 "flows",
581 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800582 tag + "_FlowsBefore",
583 cliPort=main.Cluster.active(0).CLI.karafPort )
Devin Lim142b5342017-07-20 15:22:39 -0700584 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700585 "groups",
586 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800587 tag + "_GroupsBefore",
588 cliPort=main.Cluster.active(0).CLI.karafPort )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700589
590 @staticmethod
Pier6a0c4de2018-03-18 16:01:30 -0700591 def checkDevices( main, switches, tag="", sleep=10 ):
592 main.step(
593 "Check whether the switches count is equal to %s" % switches )
594 if tag == "":
595 tag = 'CASE%d' % main.CurrentTestCaseNumber
596 result = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
597 main.FALSE,
598 kwargs={ 'numoswitch': switches},
599 attempts=10,
600 sleep=sleep )
601 utilities.assert_equals( expect=main.TRUE, actual=result,
602 onpass="Device up successful",
603 onfail="Failed to boot up devices?" )
604
605 @staticmethod
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800606 def checkFlowsByDpid( main, dpid, minFlowCount, sleep=10 ):
607 main.step(
Jon Hall39570262020-11-17 12:18:19 -0800608 "Check whether the flow count of device %s >= than %s" % ( dpid, minFlowCount ) )
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800609 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
610 main.FALSE,
611 args=( dpid, minFlowCount ),
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800612 attempts=5,
613 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800614 if count == main.FALSE:
615 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800616 utilities.assertEquals(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800617 expect=True,
Jon Hall39570262020-11-17 12:18:19 -0800618 actual=( count >= minFlowCount ),
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800619 onpass="Flow count looks correct: " + str( count ),
steven30801eccfe212019-01-24 13:00:42 +0800620 onfail="Flow count looks wrong: " + str( count ) )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800621
622 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700623 def checkFlowEqualityByDpid( main, dpid, flowCount, sleep=10 ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800624 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700625 "Check whether the flow count of device %s is equal to %s" % ( dpid, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800626 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
627 main.FALSE,
Jon Hall9677ed32018-04-24 11:16:23 -0700628 args=( dpid, flowCount, False, 1 ),
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800629 attempts=5,
630 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800631 if count == main.FALSE:
632 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800633 utilities.assertEquals(
634 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800635 actual=( count == flowCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700636 onpass="Flow count looks correct: " + str( count ) ,
637 onfail="Flow count looks wrong. found {}, should be {}.".format( count, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800638
639 @staticmethod
640 def checkGroupEqualityByDpid( main, dpid, groupCount, sleep=10):
641 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700642 "Check whether the group count of device %s is equal to %s" % ( dpid, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800643 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkGroupAddedCount,
644 main.FALSE,
645 args=( dpid, groupCount, False, 1),
646 attempts=5,
647 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800648 if count == main.FALSE:
steven3080123997972019-01-29 17:01:40 +0800649 count = main.Cluster.active( 0 ).CLI.checkGroupAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800650 utilities.assertEquals(
651 expect=True,
652 actual=( count == groupCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700653 onpass="Group count looks correct: " + str( count ) ,
654 onfail="Group count looks wrong. found {}, should be {}.".format( count, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800655
656 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700657 def checkFlowsGroupsFromFile( main ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800658
659 for dpid, values in main.count.items():
660 flowCount = values["flows"]
661 groupCount = values["groups"]
Jon Hall9677ed32018-04-24 11:16:23 -0700662 main.log.report( "Check flow count for dpid " + str( dpid ) +
663 ", should be " + str( flowCount ) )
664 Testcaselib.checkFlowEqualityByDpid( main, dpid, flowCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800665
Jon Hall9677ed32018-04-24 11:16:23 -0700666 main.log.report( "Check group count for dpid " + str( dpid ) +
667 ", should be " + str( groupCount ) )
668 Testcaselib.checkGroupEqualityByDpid( main, dpid, groupCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800669
670 return
671
672 @staticmethod
Jon Hall32c90f32021-06-24 16:32:44 -0700673 def pingAll( main, tag="", dumpFlows=True, acceptableFailed=0, basedOnIp=False,
Jon Hall06fd0df2021-01-25 15:50:06 -0800674 sleep=10, retryAttempts=1, skipOnFail=False, useScapy=True ):
You Wangf19d9f42018-02-23 16:34:19 -0800675 '''
You Wangba231e72018-03-01 13:18:21 -0800676 Verify connectivity between hosts according to the ping chart
677 acceptableFailed: max number of acceptable failed pings.
You Wangf19d9f42018-02-23 16:34:19 -0800678 basedOnIp: if True, run ping or ping6 based on suffix of host names
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800679 retryAttempts: the number of retry ping. Only works for IPv4 hosts.
You Wangf19d9f42018-02-23 16:34:19 -0800680 '''
You Wangba231e72018-03-01 13:18:21 -0800681 main.log.report( "Check host connectivity" )
682 main.log.debug( "Ping chart: %s" % main.pingChart )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800683 if tag == "":
684 tag = 'CASE%d' % main.CurrentTestCaseNumber
685 for entry in main.pingChart.itervalues():
You Wangba231e72018-03-01 13:18:21 -0800686 main.log.debug( "Entry in ping chart: %s" % entry )
687 expect = entry[ 'expect' ]
688 if expect == "Unidirectional":
689 # Verify ping from each src host to each dst host
690 src = entry[ 'src' ]
691 dst = entry[ 'dst' ]
692 expect = main.TRUE
693 main.step( "Verify unidirectional connectivity from %s to %s with tag %s" % ( str( src ), str( dst ), tag ) )
694 if basedOnIp:
695 if ("v4" in src[0]):
696 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
697 utilities.assert_equals( expect=expect, actual=pa,
698 onpass="IPv4 connectivity successfully tested",
699 onfail="IPv4 connectivity failed" )
700 if ("v6" in src[0]):
701 pa = main.Network.pingallHostsUnidirectional( src, dst, ipv6=True, acceptableFailed=acceptableFailed )
702 utilities.assert_equals( expect=expect, actual=pa,
703 onpass="IPv6 connectivity successfully tested",
704 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700705 elif main.physicalNet:
706 pa = main.NetworkBench.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed, useScapy=True )
707 utilities.assert_equals( expect=expect, actual=pa,
708 onpass="IP connectivity successfully tested",
709 onfail="IP connectivity failed" )
710
You Wangba231e72018-03-01 13:18:21 -0800711 else:
712 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
713 utilities.assert_equals( expect=expect, actual=pa,
714 onpass="IP connectivity successfully tested",
715 onfail="IP connectivity failed" )
716 else:
717 # Verify ping between each host pair
718 hosts = entry[ 'hosts' ]
719 try:
720 expect = main.TRUE if str(expect).lower() == 'true' else main.FALSE
721 except:
722 expect = main.FALSE
723 main.step( "Verify full connectivity for %s with tag %s" % ( str( hosts ), tag ) )
724 if basedOnIp:
725 if ("v4" in hosts[0]):
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800726 pa = utilities.retry( main.Network.pingallHosts,
727 main.FALSE if expect else main.TRUE,
Jon Hall43060f62020-06-23 13:13:33 -0700728 args=(hosts, ),
729 kwargs={ 'ipv6': False },
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800730 attempts=retryAttempts,
731 sleep=sleep )
You Wangba231e72018-03-01 13:18:21 -0800732 utilities.assert_equals( expect=expect, actual=pa,
733 onpass="IPv4 connectivity successfully tested",
734 onfail="IPv4 connectivity failed" )
735 if ("v6" in hosts[0]):
736 pa = main.Network.pingIpv6Hosts( hosts, acceptableFailed=acceptableFailed )
737 utilities.assert_equals( expect=expect, actual=pa,
738 onpass="IPv6 connectivity successfully tested",
739 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700740 elif main.physicalNet:
Jon Hall06fd0df2021-01-25 15:50:06 -0800741 pa = main.Network.pingallHosts( hosts, ipv6=True, useScapy=useScapy )
Jon Hall43060f62020-06-23 13:13:33 -0700742 utilities.assert_equals( expect=expect, actual=pa,
743 onpass="IP connectivity successfully tested",
744 onfail="IP connectivity failed" )
You Wangba231e72018-03-01 13:18:21 -0800745 else:
You Wangf19d9f42018-02-23 16:34:19 -0800746 pa = main.Network.pingallHosts( hosts )
747 utilities.assert_equals( expect=expect, actual=pa,
You Wangba231e72018-03-01 13:18:21 -0800748 onpass="IP connectivity successfully tested",
749 onfail="IP connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700750 if pa != expect:
You Wang5df1c6d2018-04-06 18:02:02 -0700751 Testcaselib.saveOnosDiagnostics( main )
Jon Hall43060f62020-06-23 13:13:33 -0700752 if skipOnFail and pa != expect:
You Wang24ad2f52018-04-10 10:47:12 -0700753 Testcaselib.cleanup( main, copyKarafLog=False )
You Wang5df1c6d2018-04-06 18:02:02 -0700754 main.skipCase()
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800755
Jon Hall32c90f32021-06-24 16:32:44 -0700756 if dumpFlows:
757 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
758 "flows",
759 main.logdir,
760 tag + "_FlowsOn",
761 cliPort=main.Cluster.active(0).CLI.karafPort )
762 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
763 "groups",
764 main.logdir,
765 tag + "_GroupsOn",
766 cliPort=main.Cluster.active(0).CLI.karafPort )
767
768 @staticmethod
769 def pingAllFabricIntfs( main, srcList, tag="", dumpFlows=True, skipOnFail=False ):
770 '''
771 Verify connectivity between hosts and their fabric interfaces
772 '''
773 main.log.report( "Check host connectivity with fabric" )
774 if tag == "":
775 tag = 'CASE%d' % main.CurrentTestCaseNumber
776 expect = main.TRUE
777 import json
778 import re
779 hostsJson = json.loads( main.Cluster.active( 0 ).hosts() )
780 netcfgJson = json.loads( main.Cluster.active( 0 ).getNetCfg( subjectClass='ports') )
781 for hostname in srcList:
782 try:
783 hostComponent = main.Network.hosts[ str( hostname ) ]
784 srcIface = hostComponent.interfaces[0].get( 'name' )
785 main.step( "Verify fabric connectivity for %s with tag %s" % ( str( hostname ), tag ) )
786 #Get host location, check netcfg for that port's ip
787 hostIp = hostComponent.getIPAddress( iface=srcIface )
788 main.log.warn( "Looking for %s" % hostIp )
789 ips = []
790 for obj in hostsJson:
791 if hostIp in obj['ipAddresses']:
792 for location in obj['locations']:
793 main.log.debug( location )
794 did = location['elementId'].encode( 'utf-8' )
795 port = location['port'].encode( 'utf-8' )
796 m = re.search( '\((\d+)\)', port )
797 if m:
798 port = m.group(1)
799 portId = "%s/%s" % ( did, port )
800 # Lookup ip assigned to this network port
801 ips.extend( [ x.encode( 'utf-8' ) for x in netcfgJson[ portId ][ 'interfaces' ][0][ 'ips' ] ] )
802 ips = set( ips )
803 ipRE = r'(\d+\.\d+\.\d+\.\d+)/\d+|([\w,:]*)/\d+'
804 for ip in ips:
805 ipMatch = re.search( ipRE, ip )
806 if ipMatch:
807 fabricIntfIp = ipMatch.group(1)
808 main.log.debug( "Found %s as gateway ip for %s" % ( fabricIntfIp, hostname ) )
809 pa = hostComponent.ping( fabricIntfIp, interface=srcIface )
810 utilities.assert_equals( expect=expect, actual=pa,
811 onpass="IP connectivity successfully tested",
812 onfail="IP connectivity failed" )
813 if pa != expect:
814 Testcaselib.saveOnosDiagnostics( main )
815 if skipOnFail:
816 Testcaselib.cleanup( main, copyKarafLog=False )
817 main.skipCase()
818 except ValueError:
819 main.log.exception( "Could not get gateway ip for %s" % hostname )
820
821 if dumpFlows:
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800822 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
823 "flows",
824 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800825 tag + "_FlowsOn",
826 cliPort=main.Cluster.active(0).CLI.karafPort )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800827 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
828 "groups",
829 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800830 tag + "_GroupsOn",
831 cliPort=main.Cluster.active(0).CLI.karafPort )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800832
833 @staticmethod
Jon Hall326501b2021-08-31 10:14:55 -0700834 def populateHostsVlan( main, hostList ):
835 """
836 Set the vlan for each host.
837 Checks what interface the host is configured on and reads the netcfg for that interface
838 """
839 import json
840 import re
841 hostsJson = json.loads( main.Cluster.active( 0 ).hosts() )
842 netcfgJson = json.loads( main.Cluster.active( 0 ).getNetCfg( subjectClass='ports') )
843 for hostname in hostList:
844 try:
845 hostComponent = main.Network.hosts[ str( hostname ) ]
846 srcIface = hostComponent.interfaces[0].get( 'name' )
847 #Get host location, check netcfg for that port's ip
848 hostIp = hostComponent.getIPAddress( iface=srcIface )
849 main.log.warn( "Looking for allowed vlans for %s" % hostIp )
850 vlans = []
851 for obj in hostsJson:
852 if hostIp in obj['ipAddresses']:
853 for location in obj['locations']:
854 did = location['elementId'].encode( 'utf-8' )
855 port = location['port'].encode( 'utf-8' )
856 m = re.search( '\((\d+)\)', port )
857 if m:
858 port = m.group(1)
859 portId = "%s/%s" % ( did, port )
860 # Lookup ip assigned to this network port
861 # Valid host vlans:
862 # None if vlan-untagged
863 # vlanid if vlan-tagged: vlanid
864 # None if vlan-native + any vlan ids from vlan-tagged
865 intf = netcfgJson[ portId ][ 'interfaces' ][0]
866 for field in intf.keys():
867 if "vlan-untagged" in field:
868 vlans.append( None )
869 if "vlan-tagged" in field:
870 vlans.append( int( intf[ field ].encode( 'utf-8' ) ) )
871 if "vlan-native" in field:
872 vlans.append( None )
873 if len( vlans ) == 0:
874 main.log.debug( "Could not find vlan setting for %s" % hostname )
875 vlans = set( vlans )
Siddeshd9840842021-08-06 19:26:05 +0000876 hostComponent.interfaces[0][ 'vlan' ] = list( vlans )
Jon Hall326501b2021-08-31 10:14:55 -0700877 main.log.debug( repr( hostComponent.interfaces[0] ) )
878 main.log.debug( repr( hostComponent.interfaces[0].get( 'vlan' ) ) )
879 except ValueError:
880 main.log.exception( "Error getting vlans for %s" % hostname )
881
882
883 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700884 def killLink( main, end1, end2, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700885 """
886 end1,end2: identify the switches, ex.: 'leaf1', 'spine1'
887 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
888 Kill a link and verify ONOS can see the proper link change
889 """
Jon Halla604fd42018-05-04 14:27:27 -0700890 if sleep is None:
891 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
892 else:
893 sleep = float( sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700894 main.step( "Kill link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700895 linkDown = main.Network.link( END1=end1, END2=end2, OPTION="down" )
896 linkDown = linkDown and main.Network.link( END2=end1, END1=end2, OPTION="down" )
Jon Hall214f88b2020-09-21 10:21:42 -0700897 utilities.assert_equals( expect=main.TRUE, actual=linkDown,
898 onpass="Link down successful",
899 onfail="Failed to turn off link?" )
Jon Halla604fd42018-05-04 14:27:27 -0700900 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700901 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700902 "Waiting %s seconds for link down to be discovered" % sleep )
903 time.sleep( sleep )
Jon Hall214f88b2020-09-21 10:21:42 -0700904 main.step( "Checking topology after link down" )
Devin Lim142b5342017-07-20 15:22:39 -0700905 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700906 main.FALSE,
907 kwargs={ 'numoswitch': switches,
908 'numolink': links },
909 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700910 sleep=sleep )
Jon Hall214f88b2020-09-21 10:21:42 -0700911 utilities.assert_equals( expect=main.TRUE, actual=topology,
912 onpass="Topology after link down is correct",
913 onfail="Topology after link down is incorrect" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700914
915 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700916 def killLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800917 """
918 links = list of links (src, dst) to bring down.
919 """
920
921 main.step("Killing a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700922 if sleep is None:
923 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
924 else:
925 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800926
927 for end1, end2 in links:
928 main.Network.link( END1=end1, END2=end2, OPTION="down")
929 main.Network.link( END1=end2, END2=end1, OPTION="down")
930
Jon Halla604fd42018-05-04 14:27:27 -0700931 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800932 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700933 "Waiting %s seconds for links down to be discovered" % sleep )
934 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800935
936 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
937 main.FALSE,
938 kwargs={ 'numoswitch': switches,
939 'numolink': linksAfter },
940 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700941 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800942
You Wang2854bce2018-03-30 10:15:32 -0700943 utilities.assert_equals( expect=main.TRUE, actual=topology,
944 onpass="Link batch down successful",
945 onfail="Link batch down failed" )
946
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800947 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700948 def restoreLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800949 """
950 links = list of link (src, dst) to bring up again.
951 """
952
953 main.step("Restoring a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700954 if sleep is None:
955 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
956 else:
957 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800958
959 for end1, end2 in links:
960 main.Network.link( END1=end1, END2=end2, OPTION="up")
961 main.Network.link( END1=end2, END2=end1, OPTION="up")
962
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800963 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700964 "Waiting %s seconds for links up to be discovered" % sleep )
965 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800966
967 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
968 main.FALSE,
969 kwargs={ 'numoswitch': switches,
970 'numolink': linksAfter },
971 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700972 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800973
You Wang2854bce2018-03-30 10:15:32 -0700974 utilities.assert_equals( expect=main.TRUE, actual=topology,
975 onpass="Link batch up successful",
976 onfail="Link batch up failed" )
977
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800978 @staticmethod
You Wang85747762018-05-11 15:51:50 -0700979 def disablePortBatch( main, ports, switches=None, links=None, sleep=None ):
980 """
981 Disable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
982 ports: a list of ports to disable ex. [ [ "of:0000000000000001", 1 ] ]
983 switches, links: number of expected switches and links after link change, ex.: '4', '6'
984 """
985 if sleep is None:
986 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
987 else:
988 sleep = float( sleep )
989 main.step( "Disable a batch of ports" )
990 for dpid, port in ports:
991 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="disable" )
992 main.log.info( "Waiting {} seconds for port down to be discovered".format( sleep ) )
993 time.sleep( sleep )
994 if switches and links:
995 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
996 numolink=links )
997 utilities.assert_equals( expect=main.TRUE, actual=result,
998 onpass="Port down successful",
999 onfail="Port down failed" )
1000
1001 @staticmethod
1002 def enablePortBatch( main, ports, switches, links, sleep=None ):
1003 """
1004 Enable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
1005 ports: a list of ports to enable ex. [ [ "of:0000000000000001", 1 ] ]
1006 switches, links: number of expected switches and links after link change, ex.: '4', '6'
1007 """
1008 if sleep is None:
1009 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
1010 else:
1011 sleep = float( sleep )
1012 main.step( "Enable a batch of ports" )
1013 for dpid, port in ports:
1014 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="enable" )
1015 main.log.info( "Waiting {} seconds for port up to be discovered".format( sleep ) )
1016 time.sleep( sleep )
1017 if switches and links:
1018 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
1019 numolink=links )
1020 utilities.assert_equals( expect=main.TRUE, actual=result,
1021 onpass="Port up successful",
1022 onfail="Port up failed" )
1023
1024 @staticmethod
You Wangc02d8352018-04-17 16:42:10 -07001025 def restoreLink( main, end1, end2, switches, links,
Jon Halla604fd42018-05-04 14:27:27 -07001026 portUp=False, dpid1='', dpid2='', port1='', port2='', sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001027 """
1028 Params:
1029 end1,end2: identify the end switches, ex.: 'leaf1', 'spine1'
You Wangc02d8352018-04-17 16:42:10 -07001030 portUp: enable portstate after restoring link
Jon Hall1efcb3f2016-08-23 13:42:15 -07001031 dpid1, dpid2: dpid of the end switches respectively, ex.: 'of:0000000000000002'
1032 port1, port2: respective port of the end switches that connects to the link, ex.:'1'
1033 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
1034 Kill a link and verify ONOS can see the proper link change
1035 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001036 main.step( "Restore link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -07001037 if sleep is None:
1038 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
1039 else:
1040 sleep = float( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001041 result = False
1042 count = 0
1043 while True:
1044 count += 1
Jon Halla604fd42018-05-04 14:27:27 -07001045 ctrl = main.Cluster.next()
You Wangd5873482018-01-24 12:30:00 -08001046 main.Network.link( END1=end1, END2=end2, OPTION="up" )
1047 main.Network.link( END2=end1, END1=end2, OPTION="up" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001048 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -07001049 "Waiting %s seconds for link up to be discovered" % sleep )
1050 time.sleep( sleep )
Pierfb719b12016-09-19 14:51:44 -07001051
You Wangc02d8352018-04-17 16:42:10 -07001052 if portUp:
1053 ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
1054 ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
Jon Hall43060f62020-06-23 13:13:33 -07001055 main.log.info(
1056 "Waiting %s seconds for link up to be discovered" % sleep )
Jon Halla604fd42018-05-04 14:27:27 -07001057 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001058
Jon Halla604fd42018-05-04 14:27:27 -07001059 result = ctrl.CLI.checkStatus( numoswitch=switches,
1060 numolink=links )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001061 if count > 5 or result:
1062 break
1063 utilities.assert_equals( expect=main.TRUE, actual=result,
1064 onpass="Link up successful",
1065 onfail="Failed to bring link up" )
1066
1067 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001068 def killSwitch( main, switch, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001069 """
1070 Params: switches, links: number of expected switches and links after SwitchDown, ex.: '4', '6'
1071 Completely kill a switch and verify ONOS can see the proper change
1072 """
Jon Halla604fd42018-05-04 14:27:27 -07001073 if sleep is None:
1074 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
1075 else:
1076 sleep = float( sleep )
You Wangc02d8352018-04-17 16:42:10 -07001077 switch = switch if isinstance( switch, list ) else [ switch ]
1078 main.step( "Kill " + str( switch ) )
1079 for s in switch:
1080 main.log.info( "Stopping " + s )
1081 main.Network.switch( SW=s, OPTION="stop" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001082 # todo make this repeatable
Jon Halla604fd42018-05-04 14:27:27 -07001083
1084 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -07001085 main.log.info( "Waiting %s seconds for switch down to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -07001086 sleep ) )
1087 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -07001088 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001089 main.FALSE,
1090 kwargs={ 'numoswitch': switches,
1091 'numolink': links },
1092 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -07001093 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001094 utilities.assert_equals( expect=main.TRUE, actual=topology,
1095 onpass="Kill switch successful",
1096 onfail="Failed to kill switch?" )
1097
1098 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001099 def recoverSwitch( main, switch, switches, links, rediscoverHosts=False, hostsToDiscover=[], sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001100 """
1101 Params: switches, links: number of expected switches and links after SwitchUp, ex.: '4', '6'
1102 Recover a switch and verify ONOS can see the proper change
1103 """
Jon Halla604fd42018-05-04 14:27:27 -07001104 if sleep is None:
1105 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
1106 else:
1107 sleep = float( sleep )
1108 # TODO make this repeatable
You Wangc02d8352018-04-17 16:42:10 -07001109 switch = switch if isinstance( switch, list ) else [ switch ]
1110 main.step( "Recovering " + str( switch ) )
1111 for s in switch:
1112 main.log.info( "Starting " + s )
1113 main.Network.switch( SW=s, OPTION="start" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001114 main.log.info( "Waiting %s seconds for switch up to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -07001115 sleep ) )
1116 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -07001117 if rediscoverHosts:
You Wang48381752018-05-07 13:50:57 -07001118 main.Network.discoverHosts( hostList=hostsToDiscover )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -07001119 main.log.info( "Waiting %s seconds for hosts to get re-discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -07001120 sleep ) )
1121 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -07001122
Devin Lim142b5342017-07-20 15:22:39 -07001123 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001124 main.FALSE,
1125 kwargs={ 'numoswitch': switches,
1126 'numolink': links },
1127 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -07001128 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001129 utilities.assert_equals( expect=main.TRUE, actual=topology,
1130 onpass="Switch recovery successful",
1131 onfail="Failed to recover switch?" )
1132
Jonghwan Hyun25c98a62018-05-04 13:59:09 -07001133 @staticmethod
You Wang0f745de2018-07-27 15:49:22 -07001134 def killRouter( main, router, sleep=None ):
1135 """
1136 Kill bgpd process on a quagga router
1137 router: name of the router to be killed. E.g. "bgp1"
1138 """
1139 sleep = float( sleep )
1140 main.step( "Kill " + str( router ) )
1141 if hasattr( main, 'Mininet1' ):
1142 main.Mininet1.handle.sendline( "px {}.stopProtocols()".format( router ) )
1143 main.Mininet1.handle.expect( "mininet>" )
1144 else:
1145 # TODO: support killing router in physical network
1146 pass
1147 main.log.info( "Waiting %s seconds for router down to be discovered" % ( sleep ) )
1148 time.sleep( sleep )
1149
1150 @staticmethod
1151 def recoverRouter( main, router, sleep=None ):
1152 """
1153 Restart bgpd process on a quagga router
1154 router: name of the router to be recovered. E.g. "bgp1"
1155 """
1156 sleep = float( sleep )
1157 main.step( "Recovering " + str( router ) )
1158 if hasattr( main, 'Mininet1' ):
1159 main.Mininet1.handle.sendline( "px {}.startProtocols()".format( router ) )
1160 main.Mininet1.handle.expect( "mininet>" )
1161 else:
1162 # TODO: support recovering router in physical network
1163 pass
1164 main.log.info( "Waiting %s seconds for router up to be discovered" % ( sleep ) )
1165 time.sleep( sleep )
1166
1167 @staticmethod
You Wang5da39c82018-04-26 22:55:08 -07001168 def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001169 """
1170 Stop Onos-cluster.
1171 Stops Mininet
1172 Copies ONOS log
1173 """
You Wang4cc61912018-08-28 10:10:58 -07001174 from tests.dependencies.utils import Utils
1175 main.utils = Utils()
Jon Hall627b1572020-12-01 12:01:15 -08001176 if not main.persistentSetup:
1177 for ctrl in main.Cluster.active():
1178 ctrl.CLI.log( "\"Ending Test - Shutting down ONOS and Network\"", level="INFO" )
You Wang4cc61912018-08-28 10:10:58 -07001179 # Clean up scapy hosts
You Wange24d6272018-03-27 21:18:50 -07001180 if hasattr( main, "scapyHosts" ):
1181 scapyResult = main.TRUE
1182 for host in main.scapyHosts:
1183 scapyResult = host.stopScapy() and scapyResult
1184 main.log.info( "Stopped Scapy Host: {0}".format( host.name ) )
1185 for host in main.scapyHosts:
You Wang4cc61912018-08-28 10:10:58 -07001186 if hasattr( main, 'Mininet1' ):
1187 scapyResult = main.Scapy.removeHostComponent( host.name ) and scapyResult
1188 else:
1189 scapyResult = main.Network.removeHostComponent( host.name ) and scapyResult
You Wange24d6272018-03-27 21:18:50 -07001190 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
1191 main.scapyHosts = []
1192
You Wang5da39c82018-04-26 22:55:08 -07001193 if removeHostComponent:
Jon Hall22a3bcf2021-07-23 11:40:11 -07001194 try:
1195 for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
1196 if hasattr( main, host ):
1197 if hasattr( main, 'Mininet1' ):
1198 pass
1199 else:
1200 getattr( main, host ).disconnectInband()
1201 main.Network.removeHostComponent( host )
1202 except AttributeError as e:
1203 main.log.warn( "Could not cleanup host components: " + repr( e ) )
You Wang5da39c82018-04-26 22:55:08 -07001204
You Wang5df1c6d2018-04-06 18:02:02 -07001205 if hasattr( main, 'Mininet1' ):
Pier6a0c4de2018-03-18 16:01:30 -07001206 main.utils.mininetCleanup( main.Mininet1 )
You Wang4cc61912018-08-28 10:10:58 -07001207 else:
1208 main.Network.disconnectInbandHosts()
1209 main.Network.disconnectFromNet()
Devin Lim58046fa2017-07-05 16:55:00 -07001210
You Wang5df1c6d2018-04-06 18:02:02 -07001211 if copyKarafLog:
1212 main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=True, includeCaseDesc=False )
Devin Lim58046fa2017-07-05 16:55:00 -07001213
Jon Hall627b1572020-12-01 12:01:15 -08001214 if not main.persistentSetup:
1215 for ctrl in main.Cluster.active():
1216 main.ONOSbench.onosStop( ctrl.ipAddress )
Jon Hall06fd0df2021-01-25 15:50:06 -08001217 else:
1218 Testcaselib.resetOnosLogLevels( main )
Jon Hall43060f62020-06-23 13:13:33 -07001219 Testcaselib.mnDockerTeardown( main )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001220
1221 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001222 def verifyNodes( main ):
1223 """
1224 Verifies Each active node in the cluster has an accurate view of other node's and their status
1225
1226 Params:
1227 nodes, integer array with position of the ONOS nodes in the CLIs array
1228 """
1229 nodeResults = utilities.retry( main.Cluster.nodesCheck,
1230 False,
1231 attempts=10,
1232 sleep=10 )
1233 utilities.assert_equals( expect=True, actual=nodeResults,
1234 onpass="Nodes check successful",
1235 onfail="Nodes check NOT successful" )
1236
1237 if not nodeResults:
1238 for ctrl in main.Cluster.runningNodes:
1239 main.log.debug( "{} components not ACTIVE: \n{}".format(
1240 ctrl.name,
Jon Hall6c9e2da2018-11-06 12:01:23 -08001241 ctrl.CLI.sendline( "onos:scr-list | grep -v ACTIVE" ) ) )
You Wang0bed5932018-12-11 14:45:41 -08001242 main.log.error( "Failed to verify nodes, stopping test" )
Jon Halla604fd42018-05-04 14:27:27 -07001243 main.cleanAndExit()
1244
1245 @staticmethod
Jon Hall39570262020-11-17 12:18:19 -08001246 def verifyTopology( main, switches, links, expNodes, SCCs=1 ):
Jon Halla604fd42018-05-04 14:27:27 -07001247 """
1248 Verifies that the ONOS cluster has an acuurate view of the topology
1249
1250 Params:
1251 switches, links, expNodes: number of expected switches, links, and nodes at this point in the test ex.: '4', '6', '2'
Jon Hall39570262020-11-17 12:18:19 -08001252 SCCs = Number of connected topology clusters within the control plane, defaults to 1
Jon Halla604fd42018-05-04 14:27:27 -07001253 """
1254 main.step( "Check number of topology elements" )
1255 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
1256 main.FALSE,
1257 kwargs={ 'numoswitch': switches,
1258 'numolink': links,
Jon Hall39570262020-11-17 12:18:19 -08001259 'numoctrl': expNodes,
1260 'numoSCCs': SCCs },
Jon Halla604fd42018-05-04 14:27:27 -07001261 attempts=10,
1262 sleep=12 )
1263 utilities.assert_equals( expect=main.TRUE, actual=topology,
1264 onpass="Number of topology elements are correct",
Jon Hall39570262020-11-17 12:18:19 -08001265 onfail="Unexpected number of links, switches, and/or controllers: " + main.TOPOOUTPUT )
Jon Halla604fd42018-05-04 14:27:27 -07001266
1267 @staticmethod
1268 def killOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001269 """
1270 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1271 switches, links, nodes: number of expected switches, links and nodes after KillOnos, ex.: '4', '6'
1272 Completely Kill an ONOS instance and verify the ONOS cluster can see the proper change
1273 """
Jon Halla604fd42018-05-04 14:27:27 -07001274 # TODO: We have enough information in the Cluster instance to remove expNodes from here and verifyTopology
Jon Hall3c910162018-03-07 14:42:16 -08001275 main.step( "Killing ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001276 if sleep is None:
1277 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1278 else:
1279 sleep = float( sleep )
Pier3b58c652016-09-26 12:03:31 -07001280
Jon Hall214f88b2020-09-21 10:21:42 -07001281 stepResult = main.TRUE
Jon Hall1efcb3f2016-08-23 13:42:15 -07001282 for i in nodes:
Jon Hall214f88b2020-09-21 10:21:42 -07001283 node = main.Cluster.runningNodes[ i ]
1284 if node.inDocker:
1285 killResult = node.server.dockerStop( node.name )
1286 else:
1287 killResult = main.ONOSbench.onosDie( node.ipAddress )
1288 stepResult = stepResult and killResult
Devin Lim142b5342017-07-20 15:22:39 -07001289 main.Cluster.runningNodes[ i ].active = False
Jon Hall214f88b2020-09-21 10:21:42 -07001290 utilities.assert_equals( expect=main.TRUE, actual=stepResult,
1291 onpass="ONOS instance Killed",
1292 onfail="Error killing ONOS instance" )
Jon Halla604fd42018-05-04 14:27:27 -07001293 main.Cluster.reset()
Jon Hall43060f62020-06-23 13:13:33 -07001294 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001295 time.sleep( sleep )
Pier3b58c652016-09-26 12:03:31 -07001296
Devin Lim142b5342017-07-20 15:22:39 -07001297 if len( nodes ) < main.Cluster.numCtrls:
Jon Halla604fd42018-05-04 14:27:27 -07001298 Testcaselib.verifyNodes( main )
1299 Testcaselib.verifyTopology( main, switches, links, expNodes )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001300
1301 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001302 def recoverOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001303 """
1304 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1305 switches, links, nodes: number of expected switches, links and nodes after recoverOnos, ex.: '4', '6'
1306 Recover an ONOS instance and verify the ONOS cluster can see the proper change
1307 """
Jon Hall3c910162018-03-07 14:42:16 -08001308 main.step( "Recovering ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001309 if sleep is None:
1310 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1311 else:
1312 sleep = float( sleep )
Jon Hall214f88b2020-09-21 10:21:42 -07001313 for i in nodes:
1314 node = main.Cluster.runningNodes[ i ]
1315 if node.inDocker:
1316 main.Cluster.startONOSDockerNode( i )
1317 else:
1318 main.ONOSbench.onosStart( node.ipAddress )
Jon Hall43060f62020-06-23 13:13:33 -07001319 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001320 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001321 for i in nodes:
Jon Hall39570262020-11-17 12:18:19 -08001322 node = main.Cluster.runningNodes[ i ]
Jon Hall214f88b2020-09-21 10:21:42 -07001323 if node.inDocker:
1324 isUp = node.CLI.dockerExec( node.name, dockerPrompt=node.dockerPrompt )
1325 isUp = isUp and node.CLI.prepareForCLI()
1326 isUp = isUp and node.CLI.onosSecureSSH( userName=node.karafUser, userPWD=node.karafPass )
1327 else:
1328 isUp = main.ONOSbench.isup( node.ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001329 utilities.assert_equals( expect=main.TRUE, actual=isUp,
1330 onpass="ONOS service is ready",
1331 onfail="ONOS service did not start properly" )
1332 for i in nodes:
1333 main.step( "Checking if ONOS CLI is ready" )
Devin Lim142b5342017-07-20 15:22:39 -07001334 ctrl = main.Cluster.runningNodes[ i ]
Jonghwan Hyun76a02b72018-01-30 16:40:48 +09001335 # ctrl.CLI.startCellCli()
Devin Lim142b5342017-07-20 15:22:39 -07001336 cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
1337 commandlineTimeout=60,
1338 onosStartTimeout=100 )
1339 ctrl.active = True
Jon Hall1efcb3f2016-08-23 13:42:15 -07001340 utilities.assert_equals( expect=main.TRUE,
1341 actual=cliResult,
1342 onpass="ONOS CLI is ready",
1343 onfail="ONOS CLI is not ready" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001344
Jon Halla604fd42018-05-04 14:27:27 -07001345 main.Cluster.reset()
Pier3b58c652016-09-26 12:03:31 -07001346 main.step( "Checking ONOS nodes" )
Jon Halla604fd42018-05-04 14:27:27 -07001347 Testcaselib.verifyNodes( main )
1348 Testcaselib.verifyTopology( main, switches, links, expNodes )
Pier3b58c652016-09-26 12:03:31 -07001349
Devin Lim142b5342017-07-20 15:22:39 -07001350 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -07001351 [ None, main.FALSE ],
Devin Lim142b5342017-07-20 15:22:39 -07001352 attempts=10,
1353 sleep=12 )
1354 if ready:
1355 ready = main.TRUE
1356 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001357 onpass="ONOS summary command succeded",
1358 onfail="ONOS summary command failed" )
1359 if not ready:
1360 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -07001361 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -07001362
1363 @staticmethod
1364 def addHostCfg( main ):
1365 """
1366 Adds Host Configuration to ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001367 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001368 """
1369 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001370 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001371 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001372 hostCfg = json.load( template )
1373 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
1374 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001375 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001376 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1377 subjectClass="hosts",
1378 subjectKey=urllib.quote( mac,
1379 safe='' ),
1380 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001381 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
1382 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001383 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001384 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1385 subjectClass="hosts",
1386 subjectKey=urllib.quote( mac,
1387 safe='' ),
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001388 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001389 main.pingChart.update( { 'vlan1': { "expect": "True",
1390 "hosts": [ "olt1", "vsg1" ] } } )
1391 main.pingChart[ 'vlan5' ][ 'expect' ] = 0
1392 main.pingChart[ 'vlan10' ][ 'expect' ] = 0
Jon Hall10e2ab82020-09-15 17:14:54 -07001393 main.Cluster.active( 0 ).REST.setXconnect( "of:0000000000000001",
1394 vlanId=1,
1395 port1=5,
1396 port2=6 )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001397
1398 @staticmethod
1399 def delHostCfg( main ):
1400 """
1401 Removest Host Configuration from ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001402 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001403 """
1404 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001405 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001406 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001407 hostCfg = json.load( template )
1408 main.step( "Removing host configuration" )
1409 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001410 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001411 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1412 subjectKey=urllib.quote(
1413 mac,
1414 safe='' ),
1415 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001416 main.step( "Removing configuration" )
1417 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001418 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001419 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1420 subjectKey=urllib.quote(
1421 mac,
1422 safe='' ),
1423 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001424 main.step( "Removing vlan configuration" )
1425 main.pingChart[ 'vlan1' ][ 'expect' ] = 0
Jon Hall10e2ab82020-09-15 17:14:54 -07001426 main.Cluster.active( 0 ).REST.deleteXconnect( "of:0000000000000001",
1427 vlanId=1 )
You Wang53dba1e2018-02-02 17:45:44 -08001428
1429 @staticmethod
1430 def verifyNetworkHostIp( main, attempts=10, sleep=10 ):
1431 """
1432 Verifies IP address assignment from the hosts
1433 """
1434 main.step( "Verify IP address assignment from hosts" )
1435 ipResult = main.TRUE
You Wangd66de192018-04-30 17:30:12 -07001436 main.Network.update()
You Wang6acb7a42018-05-04 15:12:25 -07001437 # Find out names of disconnected hosts
1438 disconnectedHosts = []
1439 if hasattr( main, "disconnectedIpv4Hosts" ):
1440 for host in main.disconnectedIpv4Hosts:
1441 disconnectedHosts.append( host )
1442 if hasattr( main, "disconnectedIpv6Hosts" ):
1443 for host in main.disconnectedIpv6Hosts:
1444 disconnectedHosts.append( host )
You Wang53dba1e2018-02-02 17:45:44 -08001445 for hostName, ip in main.expectedHosts[ "network" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001446 # Exclude disconnected hosts
1447 if hostName in disconnectedHosts:
1448 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( hostName ) )
1449 continue
You Wang53dba1e2018-02-02 17:45:44 -08001450 ipResult = ipResult and utilities.retry( main.Network.verifyHostIp,
1451 main.FALSE,
1452 kwargs={ 'hostList': [ hostName ],
You Wangd66de192018-04-30 17:30:12 -07001453 'prefix': ip,
Jon Hall43060f62020-06-23 13:13:33 -07001454 'update': True },
You Wang53dba1e2018-02-02 17:45:44 -08001455 attempts=attempts,
1456 sleep=sleep )
1457 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1458 onpass="Verify network host IP succeded",
1459 onfail="Verify network host IP failed" )
1460
1461 @staticmethod
You Wangaec6a092018-08-06 15:36:31 -07001462 def verifyOnosHostIp( main, attempts=10, sleep=10, skipOnFail=True ):
You Wang53dba1e2018-02-02 17:45:44 -08001463 """
1464 Verifies host IP address assignment from ONOS
1465 """
1466 main.step( "Verify host IP address assignment in ONOS" )
1467 ipResult = main.TRUE
You Wang6acb7a42018-05-04 15:12:25 -07001468 # Find out IPs of disconnected hosts
1469 disconnectedIps = []
1470 if hasattr( main, "disconnectedIpv4Hosts" ):
1471 for host in main.disconnectedIpv4Hosts:
1472 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
1473 if hasattr( main, "disconnectedIpv6Hosts" ):
1474 for host in main.disconnectedIpv6Hosts:
1475 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
You Wang53dba1e2018-02-02 17:45:44 -08001476 for hostName, ip in main.expectedHosts[ "onos" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001477 # Exclude disconnected hosts
1478 if ip in disconnectedIps:
1479 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( ip ) )
1480 continue
You Wang53dba1e2018-02-02 17:45:44 -08001481 ipResult = ipResult and utilities.retry( main.Cluster.active( 0 ).verifyHostIp,
1482 main.FALSE,
1483 kwargs={ 'hostList': [ hostName ],
1484 'prefix': ip },
1485 attempts=attempts,
1486 sleep=sleep )
1487 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1488 onpass="Verify ONOS host IP succeded",
1489 onfail="Verify ONOS host IP failed" )
You Wangaec6a092018-08-06 15:36:31 -07001490 if not ipResult and skipOnFail:
1491 Testcaselib.saveOnosDiagnostics( main )
You Wang89477152018-08-07 14:19:02 -07001492 Testcaselib.cleanup( main, copyKarafLog=False )
You Wangaec6a092018-08-06 15:36:31 -07001493 main.skipCase()
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -08001494
Jonghwan Hyun812c70f2018-02-16 16:33:16 -08001495 @staticmethod
1496 def updateIntfCfg( main, connectPoint, ips=[], untagged=0, tagged=[], native=0 ):
1497 """
1498 Description:
1499 Updates interface configuration in ONOS, with given IP and vlan parameters
1500 Required:
1501 * connectPoint: connect point to update configuration
1502 Optional:
1503 * ips: list of IP addresses, combined with '/xx' subnet representation,
1504 corresponding to 'ips' field in the configuration
1505 * untagged: vlan ID as an integer, corresponding to 'vlan-untagged' field in the configuration
1506 * tagged: integer list of vlan IDs, corresponding to 'vlan-tagged' field in the configuration
1507 * native: vlan ID as an integer, corresponding to 'vlan-native' field in the configuration
1508 """
1509 cfg = dict()
1510 cfg[ "ports" ] = dict()
1511 cfg[ "ports" ][ connectPoint ] = dict()
1512 cfg[ "ports" ][ connectPoint ][ "interfaces" ] = [ dict() ]
1513 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "ips" ] = ips
1514 if untagged > 0:
1515 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-untagged" ] = untagged
1516 else:
1517 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-tagged" ] = tagged
1518 if native > 0:
1519 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-native" ] = native
1520
1521 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( json.dumps( cfg ) ) )
You Wange24d6272018-03-27 21:18:50 -07001522
1523 @staticmethod
You Wang2cb70172018-07-25 16:44:13 -07001524 def startScapyHosts( main, scapyNames=[], mininetNames=[] ):
You Wange24d6272018-03-27 21:18:50 -07001525 """
1526 Create host components and start Scapy CLIs
You Wang2cb70172018-07-25 16:44:13 -07001527 scapyNames: list of names that will be used as component names for scapy hosts
1528 mininetNames: used when scapy host names are different from the host names
1529 in Mininet. E.g. when scapyNames=['h1Scapy'], it's required to specify the
1530 name of the corresponding Mininet host by mininetNames=['h1']
You Wange24d6272018-03-27 21:18:50 -07001531 """
1532 main.step( "Start Scapy CLIs" )
You Wang4cc61912018-08-28 10:10:58 -07001533 main.scapyNames = scapyNames if scapyNames else main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
1534 main.scapyHosts = [] if not hasattr( main, "scapyHosts" ) else main.scapyHosts
You Wang2cb70172018-07-25 16:44:13 -07001535 for scapyName in main.scapyNames:
You Wang4cc61912018-08-28 10:10:58 -07001536 if hasattr( main, 'Mininet1' ):
1537 main.Scapy.createHostComponent( scapyName )
1538 scapyHandle = getattr( main, scapyName )
1539 if mininetNames:
1540 mininetName = mininetNames[ scapyNames.index( scapyName ) ]
1541 else:
1542 mininetName = None
Jon Hall43060f62020-06-23 13:13:33 -07001543 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
1544 scapyHandle.mExecDir = "/tmp"
1545 scapyHandle.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1546 main.log.debug( "start mn host component in docker" )
1547 scapyHandle.startHostCli( mininetName,
1548 execDir="/tmp",
1549 hostHome=main.params[ "MN_DOCKER" ][ "home" ] )
1550 else:
1551 main.log.debug( "start mn host component" )
1552 scapyHandle.startHostCli( mininetName )
You Wang2cb70172018-07-25 16:44:13 -07001553 else:
You Wang0fc21702018-11-02 17:49:18 -07001554 main.Network.createHostComponent( scapyName )
You Wang4cc61912018-08-28 10:10:58 -07001555 scapyHandle = getattr( main, scapyName )
1556 scapyHandle.connectInband()
1557 main.scapyHosts.append( scapyHandle )
You Wang2cb70172018-07-25 16:44:13 -07001558 scapyHandle.startScapy()
1559 scapyHandle.updateSelf()
1560 main.log.debug( scapyHandle.name )
1561 main.log.debug( scapyHandle.hostIp )
1562 main.log.debug( scapyHandle.hostMac )
1563
1564 @staticmethod
1565 def verifyTraffic( main, srcHosts, dstIp, dstHost, dstIntf, ipv6=False, expect=True, skipOnFail=True, maxRetry=2 ):
1566 """
1567 Verify unicast traffic by pinging from source hosts to the destination IP
1568 and capturing the packets at the destination host using Scapy.
1569 srcHosts: List of host names to send the ping packets
1570 dstIp: destination IP of the ping packets
1571 dstHost: host that runs Scapy to capture the packets
1572 dstIntf: name of the interface on the destination host
1573 expect: use True if the ping is expected to be captured at destination;
1574 Otherwise False
1575 skipOnFail: skip the rest of this test case if result is not expected
1576 maxRetry: number of retries allowed
1577 """
1578 from tests.dependencies.topology import Topology
1579 try:
1580 main.topo
1581 except ( NameError, AttributeError ):
1582 main.topo = Topology()
1583 main.step( "Verify traffic to {} by capturing packets on {}".format( dstIp, dstHost ) )
1584 result = main.TRUE
1585 for srcHost in srcHosts:
1586 trafficResult = main.topo.pingAndCapture( srcHost, dstIp, dstHost, dstIntf, ipv6,
1587 expect, maxRetry, True )
1588 if not trafficResult:
You Wang2cb70172018-07-25 16:44:13 -07001589 result = main.FALSE
1590 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcHost, dstIp ) )
1591 utilities.assert_equals( expect=main.TRUE,
1592 actual=result,
1593 onpass="Verify traffic to {}: Pass".format( dstIp ),
1594 onfail="Verify traffic to {}: Fail".format( dstIp ) )
1595 if skipOnFail and result != main.TRUE:
1596 Testcaselib.saveOnosDiagnostics( main )
1597 Testcaselib.cleanup( main, copyKarafLog=False )
1598 main.skipCase()
You Wange24d6272018-03-27 21:18:50 -07001599
1600 @staticmethod
You Wang547893e2018-05-08 13:34:59 -07001601 def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=1 ):
You Wange24d6272018-03-27 21:18:50 -07001602 """
1603 Verify multicast traffic using scapy
1604 """
You Wangc564c6f2018-05-01 15:24:57 -07001605 from tests.dependencies.topology import Topology
1606 try:
1607 main.topo
1608 except ( NameError, AttributeError ):
1609 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001610 main.step( "Verify {} multicast traffic".format( routeName ) )
You Wangc02d8352018-04-17 16:42:10 -07001611 routeData = main.multicastConfig[ routeName ]
1612 srcs = main.mcastRoutes[ routeName ][ "src" ]
1613 dsts = main.mcastRoutes[ routeName ][ "dst" ]
1614 main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
1615 [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
You Wang85747762018-05-11 15:51:50 -07001616 result = main.TRUE
You Wangc02d8352018-04-17 16:42:10 -07001617 for src in srcs:
1618 srcEntry = routeData[ "src" ][ src ]
1619 for dst in dsts:
1620 dstEntry = routeData[ "dst" ][ dst ]
1621 sender = getattr( main, srcEntry[ "host" ] )
1622 receiver = getattr( main, dstEntry[ "host" ] )
1623 main.Network.addRoute( str( srcEntry[ "host" ] ),
1624 str( routeData[ "group" ] ),
1625 str( srcEntry[ "interface" ] ),
1626 True if routeData[ "ipVersion" ] == 6 else False )
1627 # Build the packet
1628 sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
1629 if routeData[ "ipVersion" ] == 4:
1630 sender.buildIP( dst=str( routeData[ "group" ] ) )
1631 elif routeData[ "ipVersion" ] == 6:
1632 sender.buildIPv6( dst=str( routeData[ "group" ] ) )
1633 sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
1634 sIface = srcEntry[ "interface" ]
1635 dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
1636 pktFilter = srcEntry[ "filter" ]
1637 pkt = srcEntry[ "packet" ]
1638 # Send packet and check received packet
1639 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
You Wangc564c6f2018-05-01 15:24:57 -07001640 t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
Jon Halla604fd42018-05-04 14:27:27 -07001641 routeData[ "group" ], srcEntry[ "Ether" ] )
You Wangc564c6f2018-05-01 15:24:57 -07001642 trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
1643 expectedResult, maxRetry, True, t3Cmd )
You Wang85747762018-05-11 15:51:50 -07001644 if not trafficResult:
1645 result = main.FALSE
1646 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcEntry[ "host" ],
1647 dstEntry[ "host" ] ) )
1648 utilities.assert_equals( expect=main.TRUE,
1649 actual=result,
1650 onpass="Verify {} multicast traffic: Pass".format( routeName ),
1651 onfail="Verify {} multicast traffic: Fail".format( routeName ) )
You Wangba823f02018-05-17 13:54:08 -07001652 if skipOnFail and result != main.TRUE:
You Wang85747762018-05-11 15:51:50 -07001653 Testcaselib.saveOnosDiagnostics( main )
1654 Testcaselib.cleanup( main, copyKarafLog=False )
1655 main.skipCase()
You Wangc02d8352018-04-17 16:42:10 -07001656
1657 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001658 def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1,
You Wang54b1d672018-06-11 16:44:13 -07001659 acceptableFailed=0, skipOnFail=True, stepMsg="Verify Ping",
1660 t3Simple=True ):
You Wang5da39c82018-04-26 22:55:08 -07001661 """
1662 Verify reachability from each host in srcList to each host in dstList
1663 """
1664 from tests.dependencies.topology import Topology
1665 try:
1666 main.topo
1667 except ( NameError, AttributeError ):
1668 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001669 main.step( stepMsg )
You Wang54b1d672018-06-11 16:44:13 -07001670 pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail, t3Simple )
You Wang85747762018-05-11 15:51:50 -07001671 utilities.assert_equals( expect=main.TRUE,
1672 actual=pingResult,
1673 onpass="{}: Pass".format( stepMsg ),
1674 onfail="{}: Fail".format( stepMsg ) )
You Wang5da39c82018-04-26 22:55:08 -07001675 if not pingResult and skipOnFail:
1676 Testcaselib.saveOnosDiagnostics( main )
1677 Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
1678 main.skipCase()
You Wangbc898b82018-05-03 16:22:34 -07001679
1680 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001681 def verifyHostLocations( main, locationDict, retry=2 ):
You Wangbc898b82018-05-03 16:22:34 -07001682 """
1683 Verify if the specified host is discovered by ONOS on the given locations
1684 Required:
You Wang85747762018-05-11 15:51:50 -07001685 locationDict: a dictionary that maps host names to expected locations.
1686 locations could be a string or a list.
1687 ex. { "h1v4": ["of:0000000000000005/8"] }
You Wangbc898b82018-05-03 16:22:34 -07001688 Returns:
1689 main.TRUE if host is discovered on all locations provided, otherwise main.FALSE
1690 """
You Wang85747762018-05-11 15:51:50 -07001691 main.step( "Verify locations of hosts {}".format( locationDict.keys() ) )
1692 result = main.TRUE
1693 for hostName, locations in locationDict.items():
1694 main.log.info( "Verify host {} is discovered at {}".format( hostName, locations ) )
1695 hostIp = main.Network.getIPAddress( hostName, proto='IPV4' )
1696 if not hostIp:
1697 hostIp = main.Network.getIPAddress( hostName, proto='IPV6' )
1698 if not hostIp:
1699 main.log.warn( "Failed to find IP address for host {}, skipping location verification".format( hostName ) )
1700 result = main.FALSE
1701 continue
1702 locationResult = utilities.retry( main.Cluster.active( 0 ).CLI.verifyHostLocation,
1703 main.FALSE,
1704 args=( hostIp, locations ),
1705 attempts=retry + 1,
1706 sleep=10 )
1707 if not locationResult:
1708 result = main.FALSE
1709 main.log.warn( "location verification for host {} failed".format( hostName ) )
You Wang547893e2018-05-08 13:34:59 -07001710 utilities.assert_equals( expect=main.TRUE, actual=result,
You Wang85747762018-05-11 15:51:50 -07001711 onpass="Location verification passed",
1712 onfail="Location verification failed" )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001713
1714 @staticmethod
You Wang6e5b48e2018-07-23 16:17:38 -07001715 def moveHost( main, hostName, srcSw, dstSw, gw, macAddr=None, prefixLen=None, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001716 """
1717 Move specified host from srcSw to dstSw.
1718 If srcSw and dstSw are same, the host will be moved from current port to
1719 next available port.
1720 Required:
1721 hostName: name of the host. e.g., "h1"
1722 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1723 dstSw: name of the switch that the host will be moved to. e.g., "leaf2"
1724 gw: ip address of the gateway of the new location
1725 Optional:
1726 macAddr: if specified, change MAC address of the host to the specified MAC address.
1727 prefixLen: prefix length
1728 cfg: port configuration as JSON string
1729 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001730 vlan: vlan number of the host
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001731 """
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001732 if not hasattr( main, 'Mininet1' ):
1733 main.log.warn( "moveHost is supposed to be used only in Mininet." )
1734 return
1735
You Wang6e5b48e2018-07-23 16:17:38 -07001736 main.step( "Moving {} host {} from {} to {}".format( 'tagged' if vlan else 'untagged', hostName, srcSw, dstSw ) )
1737 main.Mininet1.moveHost( hostName, srcSw, dstSw, macAddr, prefixLen, ipv6, vlan=vlan )
1738 if not ipv6:
You Wang6260ed52018-07-18 17:54:25 -07001739 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001740 if cfg:
1741 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1742 subjectClass="ports" )
You Wang6260ed52018-07-18 17:54:25 -07001743 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001744 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang6260ed52018-07-18 17:54:25 -07001745 time.sleep( 5 )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001746
1747 main.Mininet1.discoverHosts( [ hostName, ] )
1748
1749 # Update expectedHost when MAC address is changed.
1750 if macAddr is not None:
1751 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1752 if ipAddr is not None:
1753 for hostName, ip in main.expectedHosts[ "onos" ].items():
1754 if ip == ipAddr:
1755 vlan = hostName.split( "/" )[ -1 ]
1756 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001757 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001758 break
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001759
1760 @staticmethod
1761 def moveDualHomedHost( main, hostName, srcSw, srcPairSw, dstSw, dstPairSw, gw,
You Wang6e5b48e2018-07-23 16:17:38 -07001762 macAddr=None, prefixLen=24, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001763 """
1764 Move specified dual-homed host from srcSw-srcPairSw to dstSw-dstPairSw.
1765 If srcSw-srcPairSw and dstSw-dstPairSw are same, the host will be moved from current port
1766 to next available port.
1767 Required:
1768 hostName: name of the host. e.g., "h1"
1769 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1770 srcPairSw: name of the paired-switch that the host is attached to. e.g., "leaf2"
1771 dstSw: name of the switch that the host will be moved to. e.g., "leaf1"
1772 dstPairSw: name of the paired-switch that the host will be moved to. e.g., "leaf2"
1773 gw: ip address of the gateway of the new location
1774 Optional:
1775 macAddr: if specified, change MAC address of the host to the specified MAC address.
1776 prefixLen: prefix length
1777 cfg: port configurations as JSON string
You Wang7ea90582018-07-19 15:27:58 -07001778 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001779 vlan: vlan number of the host
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001780 """
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001781 if not hasattr( main, 'Mininet1' ):
1782 main.log.warn( "moveDualHomedHost is supposed to be used only in Mininet." )
1783 return
1784
You Wang6e5b48e2018-07-23 16:17:38 -07001785 main.step( "Moving {} host {} from {} and {} to {} and {}".format( 'tagged' if vlan else 'untagged', hostName,
1786 srcSw, srcPairSw, dstSw, dstPairSw ) )
1787 main.Mininet1.moveDualHomedHost( hostName, srcSw, srcPairSw, dstSw, dstPairSw,
1788 macAddr=macAddr, prefixLen=prefixLen, ipv6=ipv6, vlan=vlan )
1789 if not ipv6:
You Wang7ea90582018-07-19 15:27:58 -07001790 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001791 if cfg:
1792 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1793 subjectClass="ports" )
You Wang7ea90582018-07-19 15:27:58 -07001794 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001795 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang7ea90582018-07-19 15:27:58 -07001796 time.sleep( 5 )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001797
1798 main.Mininet1.discoverHosts( [ hostName, ] )
1799
1800 # Update expectedHost when MAC address is changed.
1801 if macAddr is not None:
1802 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1803 if ipAddr is not None:
1804 for hostName, ip in main.expectedHosts[ "onos" ].items():
1805 if ip == ipAddr:
1806 vlan = hostName.split( "/" )[ -1 ]
1807 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001808 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jon Hall43060f62020-06-23 13:13:33 -07001809
1810 @staticmethod
1811 def mnDockerSetup( main ):
1812 """
1813 Optionally start and setup docker image for mininet
1814 """
Jon Hall9b0de1f2020-08-24 15:38:04 -07001815 try:
1816 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall43060f62020-06-23 13:13:33 -07001817
Jon Hall9b0de1f2020-08-24 15:38:04 -07001818 main.log.info( "Creating Mininet Docker" )
1819 handle = main.Mininet1.handle
1820 # build docker image
1821 dockerFilePath = "%s/../dependencies/" % main.testDir
1822 dockerName = "trellis_mininet"
1823 # Stop any leftover container
1824 main.Mininet1.dockerStop( dockerName )
1825 # TODO: assert on these docker calls
Jon Hall39570262020-11-17 12:18:19 -08001826 main.Mininet1.dockerBuild( dockerFilePath, dockerName, pull=True )
Jon Hallf6aeda22020-07-28 09:12:56 -07001827
Jon Hall9b0de1f2020-08-24 15:38:04 -07001828 confDir = "/tmp/mn_conf/"
1829 # Try to ensure the destination exists
1830 main.log.info( "Create folder for network config files" )
1831 handle.sendline( "rm -rf %s" % confDir )
1832 handle.expect( main.Mininet1.Prompt() )
1833 main.log.debug( handle.before + handle.after )
1834 handle.sendline( "mkdir -p %s" % confDir )
1835 handle.expect( main.Mininet1.Prompt() )
1836 main.log.debug( handle.before + handle.after )
Jon Hall39570262020-11-17 12:18:19 -08001837 handle.sendline( "sudo rm -rf /tmp/mn-stratum/*" )
1838 handle.expect( main.Mininet1.Prompt() )
Jon Hall9b0de1f2020-08-24 15:38:04 -07001839 # Make sure permissions are correct
1840 handle.sendline( "sudo chown %s:%s %s" % ( main.Mininet1.user_name, main.Mininet1.user_name, confDir ) )
1841 handle.expect( main.Mininet1.Prompt() )
1842 handle.sendline( "sudo chmod -R a+rwx %s" % ( confDir ) )
1843 handle.expect( main.Mininet1.Prompt() )
1844 main.log.debug( handle.before + handle.after )
1845 # Start docker container
1846 runResponse = main.Mininet1.dockerRun( main.params[ 'MN_DOCKER' ][ 'name' ],
1847 dockerName,
1848 main.params[ 'MN_DOCKER' ][ 'args' ] )
1849 if runResponse == main.FALSE:
1850 main.log.error( "Docker container already running, aborting test" )
1851 main.cleanup()
1852 main.exit()
Jon Hall43060f62020-06-23 13:13:33 -07001853
Jon Hall9b0de1f2020-08-24 15:38:04 -07001854 main.Mininet1.dockerAttach( dockerName, dockerPrompt='~#' )
1855 main.Mininet1.sudoRequired = False
Jon Hall43060f62020-06-23 13:13:33 -07001856
Jon Hall9b0de1f2020-08-24 15:38:04 -07001857 # Fow when we create component handles
1858 main.Mininet1.mExecDir = "/tmp"
1859 main.Mininet1.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1860 main.Mininet1.hostPrompt = "/home/root#"
1861
1862 # For some reason docker isn't doing this
1863 main.Mininet1.handle.sendline( "echo \"127.0.0.1 $(cat /etc/hostname)\" >> /etc/hosts" )
1864 main.Mininet1.handle.expect( "etc/hosts" )
1865 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
1866 except Exception as e:
1867 main.log.exception( "Error seting up mininet" )
Jon Hall39570262020-11-17 12:18:19 -08001868 main.skipCase( result="FAIL", msg=e )
Jon Hall43060f62020-06-23 13:13:33 -07001869
1870 @staticmethod
1871 def mnDockerTeardown( main ):
1872 """
1873 Optionally stop and cleanup docker image for mininet
1874 """
1875
1876 if hasattr( main, 'Mininet1' ):
1877 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall3c0114c2020-08-11 15:07:42 -07001878 main.log.info( "Exiting from Mininet Docker" )
Jon Hall43060f62020-06-23 13:13:33 -07001879
1880 # Detach from container
Jon Hall43060f62020-06-23 13:13:33 -07001881 try:
Jon Hall3c0114c2020-08-11 15:07:42 -07001882 main.Mininet1.dockerDisconnect()
Jon Hall43060f62020-06-23 13:13:33 -07001883 main.Mininet1.sudoRequired = True
1884 except Exception as e:
1885 main.log.error( e )
1886
Jon Hall39570262020-11-17 12:18:19 -08001887 # Save docker logs
1888 copyResult = main.ONOSbench.scp( main.Mininet1,
1889 "/tmp/mn-stratum/*",
1890 main.logdir,
1891 direction="from",
1892 options="-rp" )
1893
1894
Jon Hall43060f62020-06-23 13:13:33 -07001895 @staticmethod
1896 def setOnosConfig( main ):
1897 """
1898 Read and Set onos configurations from the params file
1899 """
1900 main.step( "Set ONOS configurations" )
1901 config = main.params.get( 'ONOS_Configuration' )
1902 if config:
1903 main.log.debug( config )
1904 checkResult = main.TRUE
1905 for component in config:
1906 for setting in config[ component ]:
1907 value = config[ component ][ setting ]
1908 check = main.Cluster.next().setCfg( component, setting, value )
1909 main.log.info( "Value was changed? {}".format( main.TRUE == check ) )
1910 checkResult = check and checkResult
1911 utilities.assert_equals( expect=main.TRUE,
1912 actual=checkResult,
1913 onpass="Successfully set config",
1914 onfail="Failed to set config" )
1915 else:
1916 main.log.warn( "No configurations were specified to be changed after startup" )
1917
1918 @staticmethod
1919 def setOnosLogLevels( main ):
1920 """
1921 Read and Set onos log levels from the params file
1922 """
1923 main.step( 'Set logging levels' )
Jon Hall06fd0df2021-01-25 15:50:06 -08001924 # Get original values incase we want to reset them
1925 ctrl = main.Cluster.active(0)
Jon Halla7b27e62021-06-29 12:13:51 -07001926 ctrl.CLI.clearBuffer( timeout=1 )
Jon Hall06fd0df2021-01-25 15:50:06 -08001927 ctrl.CLI.logList()
1928
Jon Hall43060f62020-06-23 13:13:33 -07001929 logging = True
1930 try:
1931 logs = main.params.get( 'ONOS_Logging', False )
1932 if logs:
1933 for namespace, level in logs.items():
1934 for ctrl in main.Cluster.active():
1935 ctrl.CLI.logSet( level, namespace )
1936 except AttributeError:
1937 logging = False
1938 utilities.assert_equals( expect=True, actual=logging,
1939 onpass="Set log levels",
1940 onfail="Failed to set log levels" )
Jon Hall06fd0df2021-01-25 15:50:06 -08001941
1942 @staticmethod
1943 def resetOnosLogLevels( main ):
1944 """
1945 Read and reset onos log levels to a previously read set of values
1946 """
1947 main.step( 'Reset logging levels' )
1948 # Get original values incase we want to reset them
1949 ctrl = main.Cluster.active(0)
Jon Halla7b27e62021-06-29 12:13:51 -07001950 ctrl.CLI.clearBuffer( timeout=1 )
Jon Hall06fd0df2021-01-25 15:50:06 -08001951 currentLevels = ctrl.CLI.logList( saveValues=False )
1952 origLevels = ctrl.CLI.logLevels
1953 toBeSet = {}
1954 for logger, level in currentLevels.iteritems():
1955 if logger not in origLevels:
1956 toBeSet[ logger ] = origLevels[ 'ROOT' ]
1957 else:
1958 oldLevel = origLevels[ logger ]
1959 if level != oldLevel:
1960 toBeSet[ logger ] = oldLevel
Jon Hallef1480b2021-03-31 13:37:41 -07001961 # In case a previous test didn't reset
1962 logs = main.params.get( 'ONOS_Logging_Reset', False )
1963 if logs:
1964 for namespace, level in logs.items():
1965 toBeSet[ namespace ] = level
Jon Hall06fd0df2021-01-25 15:50:06 -08001966 logging = True
1967 try:
1968 for logger, level in toBeSet.iteritems():
1969 for ctrl in main.Cluster.active():
1970 ctrl.CLI.logSet( level, logger )
1971 except AttributeError:
1972 logging = False
1973 utilities.assert_equals( expect=True, actual=logging,
1974 onpass="Reset log levels",
1975 onfail="Failed to reset log levels" )