blob: 3aba8fc6a63862b484a078afa548f284bf47abc1 [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/"
Siddeshde1d1692021-09-15 18:12:57 +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='' ):
Siddeshde1d1692021-09-15 18:12:57 +0000219 with open( "%s%s.json%s" % ( main.configPath + main.forJson,
Siddesh606bd872021-06-29 23:42:36 +0000220 main.cfgName, suffix ) ) as cfg:
221 desiredJSON = json.load ( cfg )
Siddesh1e30a922021-10-06 19:35:09 +0000222 return Testcaselib.netCfgTransition( main, desiredJSON )
Siddesh606bd872021-06-29 23:42:36 +0000223
Siddesh1e30a922021-10-06 19:35:09 +0000224 @staticmethod
225 def netCfgTransition( main, desiredJSON ):
226 returnValue = main.TRUE
227 for device in desiredJSON ["ports"].keys():
228 deviceCfg = desiredJSON[ "ports" ][ device ]
229 currentJSON = main.Cluster.active( 0 ).REST.getNetCfg( subjectClass = "ports", subjectKey = device )
230
231 currentJSON = json.loads( currentJSON )
232 if currentJSON['interfaces'][0]['ips'] != deviceCfg['interfaces'][0]['ips']:
233 currentJSON['interfaces'][0]['ips'] = deviceCfg['interfaces'][0]['ips']
Siddesh606bd872021-06-29 23:42:36 +0000234 data = { 'interfaces': currentJSON['interfaces'] }
Siddesh1e30a922021-10-06 19:35:09 +0000235 A = main.Cluster.active( 0 ).REST.setNetCfg( data , subjectClass = "ports", subjectKey = device )
236 returnValue = returnValue and A
237 currentJSON['interfaces'] = deviceCfg['interfaces']
238 data = { 'interfaces': currentJSON['interfaces'] }
239 B = main.Cluster.active( 0 ).REST.setNetCfg( data , subjectClass = "ports", subjectKey = device )
240 returnValue = returnValue and B
Siddesh606bd872021-06-29 23:42:36 +0000241 return returnValue
242
243 @staticmethod
Jon Hall10e2ab82020-09-15 17:14:54 -0700244 def loadXconnects( main, suffix='' ):
245 with open( "%s%s-xconnects.json%s" % ( main.configPath + main.forJson,
246 main.cfgName, suffix ) ) as cfg:
247 for xconnect in json.load( cfg ).get('xconnects'):
248 main.Cluster.active( 0 ).REST.setXconnectJson( xconnect )
249
250 @staticmethod
Siddesh559d7412021-10-01 06:01:55 +0000251 def loadChart( main, suffix='' ):
Devin Lim57221b02018-02-14 15:45:36 -0800252 try:
Siddesh559d7412021-10-01 06:01:55 +0000253 filename = "%s%s.chart%s" % ( main.configPath + main.forChart,
254 main.cfgName, suffix )
Jon Hall32c90f32021-06-24 16:32:44 -0700255 with open( filename ) as chart:
Jon Hall43060f62020-06-23 13:13:33 -0700256 main.pingChart = json.load( chart )
Devin Lim57221b02018-02-14 15:45:36 -0800257 except IOError:
Jon Hall32c90f32021-06-24 16:32:44 -0700258 main.log.warn( "No chart file found at %s" % filename )
Devin Lim57221b02018-02-14 15:45:36 -0800259
260 @staticmethod
261 def loadHost( main ):
262 with open( "%s%s.host" % ( main.configPath + main.forHost,
263 main.cfgName ) ) as host:
264 main.expectedHosts = json.load( host )
265
266 @staticmethod
You Wang27317572018-03-06 12:13:11 -0800267 def loadSwitchFailureChart( main ):
268 with open( "%s%s.switchFailureChart" % ( main.configPath + main.forSwitchFailure,
269 main.cfgName ) ) as sfc:
270 main.switchFailureChart = json.load( sfc )
271
272 @staticmethod
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800273 def loadLinkFailureChart( main ):
274 with open( "%s%s.linkFailureChart" % ( main.configPath + main.forLinkFailure,
You Wange24d6272018-03-27 21:18:50 -0700275 main.cfgName ) ) as lfc:
276 main.linkFailureChart = json.load( lfc )
277
278 @staticmethod
279 def loadMulticastConfig( main ):
280 with open( "%s%s.multicastConfig" % ( main.configPath + main.forMulticast,
281 main.cfgName ) ) as cfg:
282 main.multicastConfig = json.load( cfg )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800283
284 @staticmethod
Jon Hall1efcb3f2016-08-23 13:42:15 -0700285 def startMininet( main, topology, args="" ):
Jon Hall43060f62020-06-23 13:13:33 -0700286 main.log.info( "Copying mininet topology file to mininet machine" )
You Wangd87b2312018-01-30 12:47:17 -0800287 copyResult = main.ONOSbench.scp( main.Mininet1,
288 main.topoPath + main.topology,
You Wang5da39c82018-04-26 22:55:08 -0700289 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800290 direction="to" )
291 if main.topologyLib:
292 for lib in main.topologyLib.split(","):
293 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
294 main.topoPath + lib,
You Wang5da39c82018-04-26 22:55:08 -0700295 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800296 direction="to" )
297 if main.topologyConf:
You Wanga877ea42018-04-05 15:27:40 -0700298 import re
299 controllerIPs = [ ctrl.ipAddress for ctrl in main.Cluster.runningNodes ]
300 index = 0
Jon Hall43060f62020-06-23 13:13:33 -0700301 destDir = "~/"
302 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
303 destDir = "/tmp/mn_conf/"
304 # Try to ensure the destination exists
You Wangd87b2312018-01-30 12:47:17 -0800305 for conf in main.topologyConf.split(","):
You Wanga877ea42018-04-05 15:27:40 -0700306 # Update zebra configurations with correct ONOS instance IP
307 if conf in [ "zebradbgp1.conf", "zebradbgp2.conf" ]:
308 ip = controllerIPs[ index ]
309 index = ( index + 1 ) % len( controllerIPs )
310 with open( main.configPath + main.forConfig + conf ) as f:
311 s = f.read()
312 s = re.sub( r"(fpm connection ip).*(port 2620)", r"\1 " + ip + r" \2", s )
313 with open( main.configPath + main.forConfig + conf, "w" ) as f:
314 f.write( s )
You Wangd87b2312018-01-30 12:47:17 -0800315 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Devin Lim57221b02018-02-14 15:45:36 -0800316 main.configPath + main.forConfig + conf,
Jon Hall43060f62020-06-23 13:13:33 -0700317 destDir,
You Wangd87b2312018-01-30 12:47:17 -0800318 direction="to" )
You Wang68568b12019-03-04 11:49:57 -0800319 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Jon Hallbc1c1c92020-05-27 09:29:30 -0700320 main.ONOSbench.home + main.bmv2Path + main.bmv2,
You Wang68568b12019-03-04 11:49:57 -0800321 main.Mininet1.home + "custom",
322 direction="to" )
Jon Hall9b0de1f2020-08-24 15:38:04 -0700323
324 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
325 # move the config files into home
326 main.Mininet1.handle.sendline( "cp config/* . " )
327 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
328 main.log.debug( main.Mininet1.handle.before + main.Mininet1.handle.after )
329 main.Mininet1.handle.sendline( "ls -al " )
330 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
331 main.log.debug( main.Mininet1.handle.before + main.Mininet1.handle.after )
332
You Wangd87b2312018-01-30 12:47:17 -0800333 stepResult = copyResult
334 utilities.assert_equals( expect=main.TRUE,
335 actual=stepResult,
336 onpass="Successfully copied topo files",
337 onfail="Failed to copy topo files" )
Jon Halldac3eae2020-06-05 12:04:06 -0700338 if main.stratumRoot:
339 main.Mininet1.handle.sendline( "export STRATUM_ROOT=" + str( main.stratumRoot ) )
Jon Hall3c0114c2020-08-11 15:07:42 -0700340 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700341 main.step( "Starting Mininet Topology" )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700342 arg = "--onos-ip=%s %s" % (",".join([ctrl.ipAddress for ctrl in main.Cluster.runningNodes]), args)
Jon Hall1efcb3f2016-08-23 13:42:15 -0700343 main.topology = topology
344 topoResult = main.Mininet1.startNet(
You Wang5da39c82018-04-26 22:55:08 -0700345 topoFile=main.Mininet1.home + "custom/" + main.topology, args=arg )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700346 stepResult = topoResult
347 utilities.assert_equals( expect=main.TRUE,
348 actual=stepResult,
349 onpass="Successfully loaded topology",
350 onfail="Failed to load topology" )
351 # Exit if topology did not load properly
352 if not topoResult:
Devin Lim44075962017-08-11 10:56:37 -0700353 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700354 if main.useBmv2:
Jon Hall3c0114c2020-08-11 15:07:42 -0700355 main.step( "Configure switches in ONOS" )
Jon Hall43060f62020-06-23 13:13:33 -0700356 # Upload the net-cfg file created for each switch
357 filename = "onos-netcfg.json"
358 switchPrefix = main.params[ 'DEPENDENCY' ].get( 'switchPrefix', "bmv2" )
Jon Hall3c0114c2020-08-11 15:07:42 -0700359 switchNetCfg = main.TRUE
Jon Hall43060f62020-06-23 13:13:33 -0700360 for switch in main.Mininet1.getSwitches( switchRegex=r"(StratumBmv2Switch)|(Bmv2Switch)" ).keys():
361 path = "/tmp/mn-stratum/%s/" % switch
362 dstPath = "/tmp/"
363 dstFileName = "%s-onos-netcfg.json" % switch
364 main.ONOSbench1.scp( main.Mininet1,
365 "%s%s" % ( path, filename ),
366 "%s%s" % ( dstPath, dstFileName ),
367 "from" )
368 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 -0700369 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
Jon Hall43060f62020-06-23 13:13:33 -0700370 # Configure managementAddress
371 main.ONOSbench1.handle.sendline( "sudo sed -i 's/localhost/%s/g' %s%s" % ( main.Mininet1.ip_address, 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 id
375 main.ONOSbench1.handle.sendline( "sudo sed -i 's/device:%s/device:%s:%s/g' %s%s" % ( switch, switchPrefix, switch, dstPath, dstFileName ) )
376 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
377 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
378 # Configure device name
Jon Hall39570262020-11-17 12:18:19 -0800379 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 -0700380 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
381 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
Jon Hall3c0114c2020-08-11 15:07:42 -0700382 node = main.Cluster.active(0)
383 switchNetCfg = switchNetCfg and node.onosNetCfg( node.server.ip_address,
384 dstPath,
385 dstFileName,
386 user=node.REST.user_name,
387 password=node.REST.pwd )
388 # Stop test if we fail to push switch netcfg
389 utilities.assert_equals( expect=main.TRUE,
390 actual=switchNetCfg,
391 onpass="Successfully pushed switch netcfg",
392 onfail="Failed to configure switches in onos" )
393 if not switchNetCfg:
394 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700395 # Make sure hosts make some noise
396 Testcaselib.discoverHosts( main )
397
398 @staticmethod
399 def discoverHosts( main ):
400 # TODO add option to only select specific hosts
401 if hasattr( main, "Mininet1" ):
402 network = main.Mininet1
403 elif hasattr( main, "NetworkBench" ):
404 network = main.NetworkBench
405 else:
406 main.log.warn( "Could not find component for test network, skipping host discovery" )
407 return
408 network.discoverHosts()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700409
410 @staticmethod
Jon Hall06fd0df2021-01-25 15:50:06 -0800411 def connectToPhysicalNetwork( main, hostDiscovery=True ):
You Wang84f981d2018-01-12 16:11:50 -0800412 main.step( "Connecting to physical netowrk" )
Jon Hall43060f62020-06-23 13:13:33 -0700413 main.physicalNet = True
You Wang84f981d2018-01-12 16:11:50 -0800414 topoResult = main.NetworkBench.connectToNet()
415 stepResult = topoResult
416 utilities.assert_equals( expect=main.TRUE,
417 actual=stepResult,
Jon Hall43060f62020-06-23 13:13:33 -0700418 onpass="Successfully connected to topology",
419 onfail="Failed to connect to topology" )
You Wang84f981d2018-01-12 16:11:50 -0800420 # Exit if topology did not load properly
421 if not topoResult:
422 main.cleanAndExit()
423
Jon Hall627b1572020-12-01 12:01:15 -0800424 if not main.persistentSetup:
425 # Perform any optional setup
426 for switch in main.NetworkBench.switches:
427 if hasattr( switch, "setup" ):
428 switch.setup() # We might not need this
Jon Hall43060f62020-06-23 13:13:33 -0700429
Jon Hall627b1572020-12-01 12:01:15 -0800430 main.step( "Assign switches to controllers." )
431 stepResult = main.TRUE
432 switches = main.NetworkBench.getSwitches()
433 pool = []
434 for name in switches.keys():
435 # NOTE: although this terminology is ovsdb centric, we can use this function for other switches too
436 # e.g. push onos net-cfg for stratum switches
437 thread = main.Thread( target=main.NetworkBench.assignSwController,
438 name="assignSwitchToController",
439 args=[ name, main.Cluster.getIps(), '6653' ] )
440 pool.append( thread )
441 thread.start()
442 for thread in pool:
443 thread.join( 300 )
444 if not thread.result:
445 stepResult = main.FALSE
446 utilities.assert_equals( expect=main.TRUE,
447 actual=stepResult,
448 onpass="Successfully assign switches to controllers",
449 onfail="Failed to assign switches to controllers" )
You Wang84f981d2018-01-12 16:11:50 -0800450
You Wang4cc61912018-08-28 10:10:58 -0700451 # Check devices
452 Testcaselib.checkDevices( main, switches=int( main.params[ 'TOPO' ][ 'switchNum' ] ) )
You Wang4cc61912018-08-28 10:10:58 -0700453 # Connecting to hosts that only have data plane connectivity
454 main.step( "Connecting inband hosts" )
455 stepResult = main.Network.connectInbandHosts()
456 utilities.assert_equals( expect=main.TRUE,
457 actual=stepResult,
458 onpass="Successfully connected inband hosts",
459 onfail="Failed to connect inband hosts" )
Jon Hall06fd0df2021-01-25 15:50:06 -0800460 if hostDiscovery:
461 Testcaselib.discoverHosts( main )
You Wang4cc61912018-08-28 10:10:58 -0700462
You Wang84f981d2018-01-12 16:11:50 -0800463 @staticmethod
You Wang5df1c6d2018-04-06 18:02:02 -0700464 def saveOnosDiagnostics( main ):
465 """
466 Get onos-diags.tar.gz and save it to the log directory.
467 suffix: suffix string of the file name. E.g. onos-diags-case1.tar.gz
468 """
469 main.log.info( "Collecting onos-diags..." )
Jon Halla8cf76a2021-10-05 14:31:47 -0700470 podNames = []
Siddesha2938fe2021-04-06 02:46:06 +0000471 for ctrl in main.Cluster.runningNodes:
Jon Halla8cf76a2021-10-05 14:31:47 -0700472 if ctrl.k8s:
473 podNames.append( ctrl.k8s.podName )
474 else:
475 main.ONOSbench.onosDiagnostics( [ctrl.ipAddress], main.logdir, "-CASE%d" % main.CurrentTestCaseNumber, onosPortnumber=ctrl.REST.port )
476 if podNames:
477 main.ONOSbench.onosDiagnosticsK8s( podNames, main.logdir, "-CASE%d" % main.CurrentTestCaseNumber )
You Wang5df1c6d2018-04-06 18:02:02 -0700478
479 @staticmethod
Devin Lim142b5342017-07-20 15:22:39 -0700480 def config( main, cfgName ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700481 main.spines = []
Piera2a7e1b2016-10-04 11:51:43 -0700482
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700483 main.failures = int( main.params[ 'failures' ] )
484 main.cfgName = cfgName
Piera2a7e1b2016-10-04 11:51:43 -0700485
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700486 if main.cfgName == '2x2':
487 spine = {}
488 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
489 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
490 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700491
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700492 spine = {}
493 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
494 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
495 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700496
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700497 elif main.cfgName == '4x4':
498 spine = {}
499 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
500 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
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' ][ 'spine2' ]
505 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
506 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700507
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700508 spine = {}
509 spine[ 'name' ] = main.params[ 'switches' ][ 'spine3' ]
510 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid3' ]
511 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700512
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700513 spine = {}
514 spine[ 'name' ] = main.params[ 'switches' ][ 'spine4' ]
515 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid4' ]
516 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700517
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700518 else:
Piera2a7e1b2016-10-04 11:51:43 -0700519 main.log.error( "Configuration failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700520 main.cleanAndExit()
You Wang27317572018-03-06 12:13:11 -0800521
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800522 @staticmethod
523 def addStaticOnosRoute( main, subnet, intf):
524 """
525 Adds an ONOS static route with the use route-add command.
526 """
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800527 routeResult = main.Cluster.active( 0 ).addStaticRoute(subnet, intf)
528
Piera2a7e1b2016-10-04 11:51:43 -0700529 @staticmethod
You Wangc02f3be2018-05-18 12:14:23 -0700530 def checkGroupsForBuckets( main, deviceId, subnetDict, routingTable=30 ):
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700531 """
532 Check number of groups for each subnet on device deviceId and matches
533 it with an expected value. subnetDict is a dictionarty containing values
534 of the type "10.0.1.0/24" : 5.
535 """
You Wangc02f3be2018-05-18 12:14:23 -0700536 main.step( "Checking if number of groups for subnets in device {0} is as expected.".format( deviceId ) )
537 groups = main.Cluster.active( 0 ).CLI.getGroups( deviceId, groupType="select" )
538 flows = main.Cluster.active( 0 ).CLI.flows( jsonFormat=False, device=deviceId )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700539
You Wangc02f3be2018-05-18 12:14:23 -0700540 result = main.TRUE
541 for subnet, numberInSelect in subnetDict.iteritems():
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700542 for flow in flows.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700543 if "tableId={0}".format( routingTable ) in flow and subnet in flow:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700544 # this will match the group id that this flow entry points to, for example :
545 # 0x70000041 in flow entry which contains "deferred=[GROUP:0x70000041], transition=TABLE:60,"
You Wangc02f3be2018-05-18 12:14:23 -0700546 groupId = re.search( r".*GROUP:(0x.*)], transition.*", flow ).groups()[0]
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700547 count = 0
548 for group in groups.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700549 if 'id={0}'.format( groupId ) in group:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700550 count += 1
You Wangc02f3be2018-05-18 12:14:23 -0700551 if count - 1 != numberInSelect:
552 result = main.FALSE
553 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 ) )
554 utilities.assert_equals( expect=main.TRUE, actual=result,
555 onpass="All bucket numbers are as expected",
556 onfail="Some bucket numbers are not as expected" )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700557
558 @staticmethod
Jon Hall32c90f32021-06-24 16:32:44 -0700559 def checkFlows( main, minFlowCount, tag="", dumpFlows=True, sleep=10 ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700560 main.step(
Jon Hall39570262020-11-17 12:18:19 -0800561 "Check whether the flow count is >= %s" % minFlowCount )
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900562 if tag == "":
563 tag = 'CASE%d' % main.CurrentTestCaseNumber
Devin Lim142b5342017-07-20 15:22:39 -0700564 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowCount,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700565 main.FALSE,
566 kwargs={ 'min': minFlowCount },
567 attempts=10,
You Wang1cdc5f52017-12-19 16:47:51 -0800568 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800569 if count == main.FALSE:
570 count = main.Cluster.active( 0 ).CLI.checkFlowCount()
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700571 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700572 expect=True,
Jon Hall39570262020-11-17 12:18:19 -0800573 actual=( count >= minFlowCount ),
Jon Hall43060f62020-06-23 13:13:33 -0700574 onpass="Flow count looks correct; found %s, expecting at least %s" % ( count, minFlowCount ),
575 onfail="Flow count looks wrong; found %s, expecting at least %s" % ( count, minFlowCount ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700576
577 main.step( "Check whether all flow status are ADDED" )
Devin Lim142b5342017-07-20 15:22:39 -0700578 flowCheck = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowsState,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700579 main.FALSE,
580 kwargs={ 'isPENDING': False },
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800581 attempts=5,
You Wang1cdc5f52017-12-19 16:47:51 -0800582 sleep=sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700583 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700584 expect=main.TRUE,
585 actual=flowCheck,
586 onpass="Flow status is correct!",
587 onfail="Flow status is wrong!" )
Jon Hall32c90f32021-06-24 16:32:44 -0700588 if dumpFlows:
Devin Lim142b5342017-07-20 15:22:39 -0700589 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700590 "flows",
591 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800592 tag + "_FlowsBefore",
593 cliPort=main.Cluster.active(0).CLI.karafPort )
Devin Lim142b5342017-07-20 15:22:39 -0700594 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700595 "groups",
596 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800597 tag + "_GroupsBefore",
598 cliPort=main.Cluster.active(0).CLI.karafPort )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700599
600 @staticmethod
Pier6a0c4de2018-03-18 16:01:30 -0700601 def checkDevices( main, switches, tag="", sleep=10 ):
602 main.step(
603 "Check whether the switches count is equal to %s" % switches )
604 if tag == "":
605 tag = 'CASE%d' % main.CurrentTestCaseNumber
606 result = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
607 main.FALSE,
608 kwargs={ 'numoswitch': switches},
609 attempts=10,
610 sleep=sleep )
611 utilities.assert_equals( expect=main.TRUE, actual=result,
612 onpass="Device up successful",
613 onfail="Failed to boot up devices?" )
614
615 @staticmethod
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800616 def checkFlowsByDpid( main, dpid, minFlowCount, sleep=10 ):
617 main.step(
Jon Hall39570262020-11-17 12:18:19 -0800618 "Check whether the flow count of device %s >= than %s" % ( dpid, minFlowCount ) )
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800619 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
620 main.FALSE,
621 args=( dpid, minFlowCount ),
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800622 attempts=5,
623 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800624 if count == main.FALSE:
625 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800626 utilities.assertEquals(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800627 expect=True,
Jon Hall39570262020-11-17 12:18:19 -0800628 actual=( count >= minFlowCount ),
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800629 onpass="Flow count looks correct: " + str( count ),
steven30801eccfe212019-01-24 13:00:42 +0800630 onfail="Flow count looks wrong: " + str( count ) )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800631
632 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700633 def checkFlowEqualityByDpid( main, dpid, flowCount, sleep=10 ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800634 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700635 "Check whether the flow count of device %s is equal to %s" % ( dpid, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800636 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
637 main.FALSE,
Jon Hall9677ed32018-04-24 11:16:23 -0700638 args=( dpid, flowCount, False, 1 ),
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800639 attempts=5,
640 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800641 if count == main.FALSE:
642 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800643 utilities.assertEquals(
644 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800645 actual=( count == flowCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700646 onpass="Flow count looks correct: " + str( count ) ,
647 onfail="Flow count looks wrong. found {}, should be {}.".format( count, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800648
649 @staticmethod
650 def checkGroupEqualityByDpid( main, dpid, groupCount, sleep=10):
651 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700652 "Check whether the group count of device %s is equal to %s" % ( dpid, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800653 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkGroupAddedCount,
654 main.FALSE,
655 args=( dpid, groupCount, False, 1),
656 attempts=5,
657 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800658 if count == main.FALSE:
steven3080123997972019-01-29 17:01:40 +0800659 count = main.Cluster.active( 0 ).CLI.checkGroupAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800660 utilities.assertEquals(
661 expect=True,
662 actual=( count == groupCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700663 onpass="Group count looks correct: " + str( count ) ,
664 onfail="Group count looks wrong. found {}, should be {}.".format( count, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800665
666 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700667 def checkFlowsGroupsFromFile( main ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800668
669 for dpid, values in main.count.items():
670 flowCount = values["flows"]
671 groupCount = values["groups"]
Jon Hall9677ed32018-04-24 11:16:23 -0700672 main.log.report( "Check flow count for dpid " + str( dpid ) +
673 ", should be " + str( flowCount ) )
674 Testcaselib.checkFlowEqualityByDpid( main, dpid, flowCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800675
Jon Hall9677ed32018-04-24 11:16:23 -0700676 main.log.report( "Check group count for dpid " + str( dpid ) +
677 ", should be " + str( groupCount ) )
678 Testcaselib.checkGroupEqualityByDpid( main, dpid, groupCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800679
680 return
681
682 @staticmethod
Jon Hall32c90f32021-06-24 16:32:44 -0700683 def pingAll( main, tag="", dumpFlows=True, acceptableFailed=0, basedOnIp=False,
Jon Hall06fd0df2021-01-25 15:50:06 -0800684 sleep=10, retryAttempts=1, skipOnFail=False, useScapy=True ):
You Wangf19d9f42018-02-23 16:34:19 -0800685 '''
You Wangba231e72018-03-01 13:18:21 -0800686 Verify connectivity between hosts according to the ping chart
687 acceptableFailed: max number of acceptable failed pings.
You Wangf19d9f42018-02-23 16:34:19 -0800688 basedOnIp: if True, run ping or ping6 based on suffix of host names
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800689 retryAttempts: the number of retry ping. Only works for IPv4 hosts.
You Wangf19d9f42018-02-23 16:34:19 -0800690 '''
You Wangba231e72018-03-01 13:18:21 -0800691 main.log.report( "Check host connectivity" )
692 main.log.debug( "Ping chart: %s" % main.pingChart )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800693 if tag == "":
694 tag = 'CASE%d' % main.CurrentTestCaseNumber
695 for entry in main.pingChart.itervalues():
You Wangba231e72018-03-01 13:18:21 -0800696 main.log.debug( "Entry in ping chart: %s" % entry )
697 expect = entry[ 'expect' ]
698 if expect == "Unidirectional":
699 # Verify ping from each src host to each dst host
700 src = entry[ 'src' ]
701 dst = entry[ 'dst' ]
702 expect = main.TRUE
703 main.step( "Verify unidirectional connectivity from %s to %s with tag %s" % ( str( src ), str( dst ), tag ) )
704 if basedOnIp:
705 if ("v4" in src[0]):
706 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
707 utilities.assert_equals( expect=expect, actual=pa,
708 onpass="IPv4 connectivity successfully tested",
709 onfail="IPv4 connectivity failed" )
710 if ("v6" in src[0]):
711 pa = main.Network.pingallHostsUnidirectional( src, dst, ipv6=True, acceptableFailed=acceptableFailed )
712 utilities.assert_equals( expect=expect, actual=pa,
713 onpass="IPv6 connectivity successfully tested",
714 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700715 elif main.physicalNet:
716 pa = main.NetworkBench.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed, useScapy=True )
717 utilities.assert_equals( expect=expect, actual=pa,
718 onpass="IP connectivity successfully tested",
719 onfail="IP connectivity failed" )
720
You Wangba231e72018-03-01 13:18:21 -0800721 else:
722 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
723 utilities.assert_equals( expect=expect, actual=pa,
724 onpass="IP connectivity successfully tested",
725 onfail="IP connectivity failed" )
726 else:
727 # Verify ping between each host pair
728 hosts = entry[ 'hosts' ]
729 try:
730 expect = main.TRUE if str(expect).lower() == 'true' else main.FALSE
731 except:
732 expect = main.FALSE
733 main.step( "Verify full connectivity for %s with tag %s" % ( str( hosts ), tag ) )
734 if basedOnIp:
735 if ("v4" in hosts[0]):
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800736 pa = utilities.retry( main.Network.pingallHosts,
737 main.FALSE if expect else main.TRUE,
Jon Hall43060f62020-06-23 13:13:33 -0700738 args=(hosts, ),
739 kwargs={ 'ipv6': False },
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800740 attempts=retryAttempts,
741 sleep=sleep )
You Wangba231e72018-03-01 13:18:21 -0800742 utilities.assert_equals( expect=expect, actual=pa,
743 onpass="IPv4 connectivity successfully tested",
744 onfail="IPv4 connectivity failed" )
745 if ("v6" in hosts[0]):
746 pa = main.Network.pingIpv6Hosts( hosts, acceptableFailed=acceptableFailed )
747 utilities.assert_equals( expect=expect, actual=pa,
748 onpass="IPv6 connectivity successfully tested",
749 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700750 elif main.physicalNet:
Siddesh559d7412021-10-01 06:01:55 +0000751 pa = main.Network.pingallHosts( hosts, ipv6=True, useScapy=useScapy, returnResult=True )
752 combinedResult = True
753 for result in pa:
754 expectedResult = None
755 for ping in main.pingChart.values():
756 if result["src"] in ping["hosts"] and result["dst"] in ping["hosts"]:
757 # Check if the vlan in ping is the same as in the result. If true, set the expected result to result at expect
758 # If expected result is not the same as the actual result, then the combined result is false
759 # if we cannot find the expected result, then expect should be the default between the hosts
760 if str(result["vlan"]) in ping.get("vlans", [] ):
761 expectedResult = ping["vlans"].get(str(result["vlan"]))
762 if expectedResult is None:
763 expectedRresult = expect
Siddeshb86c0e92021-10-05 22:14:45 +0000764 if expectedResult.lower() == "true":
765 expectedResult = main.TRUE
766 else:
767 expectedResult = main.FALSE
Siddesh559d7412021-10-01 06:01:55 +0000768 if expectedResult != result["result"]:
769 combinedResult = False
770 utilities.assert_equals( expect=True, actual=combinedResult,
Jon Hall43060f62020-06-23 13:13:33 -0700771 onpass="IP connectivity successfully tested",
772 onfail="IP connectivity failed" )
You Wangba231e72018-03-01 13:18:21 -0800773 else:
You Wangf19d9f42018-02-23 16:34:19 -0800774 pa = main.Network.pingallHosts( hosts )
775 utilities.assert_equals( expect=expect, actual=pa,
You Wangba231e72018-03-01 13:18:21 -0800776 onpass="IP connectivity successfully tested",
777 onfail="IP connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700778 if pa != expect:
You Wang5df1c6d2018-04-06 18:02:02 -0700779 Testcaselib.saveOnosDiagnostics( main )
Jon Hall43060f62020-06-23 13:13:33 -0700780 if skipOnFail and pa != expect:
You Wang24ad2f52018-04-10 10:47:12 -0700781 Testcaselib.cleanup( main, copyKarafLog=False )
You Wang5df1c6d2018-04-06 18:02:02 -0700782 main.skipCase()
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800783
Jon Hall32c90f32021-06-24 16:32:44 -0700784 if dumpFlows:
785 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
786 "flows",
787 main.logdir,
788 tag + "_FlowsOn",
789 cliPort=main.Cluster.active(0).CLI.karafPort )
790 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
791 "groups",
792 main.logdir,
793 tag + "_GroupsOn",
794 cliPort=main.Cluster.active(0).CLI.karafPort )
795
796 @staticmethod
797 def pingAllFabricIntfs( main, srcList, tag="", dumpFlows=True, skipOnFail=False ):
798 '''
799 Verify connectivity between hosts and their fabric interfaces
800 '''
801 main.log.report( "Check host connectivity with fabric" )
802 if tag == "":
803 tag = 'CASE%d' % main.CurrentTestCaseNumber
804 expect = main.TRUE
805 import json
806 import re
807 hostsJson = json.loads( main.Cluster.active( 0 ).hosts() )
808 netcfgJson = json.loads( main.Cluster.active( 0 ).getNetCfg( subjectClass='ports') )
809 for hostname in srcList:
810 try:
811 hostComponent = main.Network.hosts[ str( hostname ) ]
812 srcIface = hostComponent.interfaces[0].get( 'name' )
813 main.step( "Verify fabric connectivity for %s with tag %s" % ( str( hostname ), tag ) )
814 #Get host location, check netcfg for that port's ip
815 hostIp = hostComponent.getIPAddress( iface=srcIface )
816 main.log.warn( "Looking for %s" % hostIp )
817 ips = []
818 for obj in hostsJson:
819 if hostIp in obj['ipAddresses']:
820 for location in obj['locations']:
821 main.log.debug( location )
822 did = location['elementId'].encode( 'utf-8' )
823 port = location['port'].encode( 'utf-8' )
824 m = re.search( '\((\d+)\)', port )
825 if m:
826 port = m.group(1)
827 portId = "%s/%s" % ( did, port )
828 # Lookup ip assigned to this network port
829 ips.extend( [ x.encode( 'utf-8' ) for x in netcfgJson[ portId ][ 'interfaces' ][0][ 'ips' ] ] )
830 ips = set( ips )
831 ipRE = r'(\d+\.\d+\.\d+\.\d+)/\d+|([\w,:]*)/\d+'
832 for ip in ips:
833 ipMatch = re.search( ipRE, ip )
834 if ipMatch:
835 fabricIntfIp = ipMatch.group(1)
836 main.log.debug( "Found %s as gateway ip for %s" % ( fabricIntfIp, hostname ) )
837 pa = hostComponent.ping( fabricIntfIp, interface=srcIface )
838 utilities.assert_equals( expect=expect, actual=pa,
839 onpass="IP connectivity successfully tested",
840 onfail="IP connectivity failed" )
841 if pa != expect:
842 Testcaselib.saveOnosDiagnostics( main )
843 if skipOnFail:
844 Testcaselib.cleanup( main, copyKarafLog=False )
845 main.skipCase()
846 except ValueError:
847 main.log.exception( "Could not get gateway ip for %s" % hostname )
848
849 if dumpFlows:
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800850 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
851 "flows",
852 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800853 tag + "_FlowsOn",
854 cliPort=main.Cluster.active(0).CLI.karafPort )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800855 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
856 "groups",
857 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800858 tag + "_GroupsOn",
859 cliPort=main.Cluster.active(0).CLI.karafPort )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800860
861 @staticmethod
Jon Hall326501b2021-08-31 10:14:55 -0700862 def populateHostsVlan( main, hostList ):
863 """
864 Set the vlan for each host.
865 Checks what interface the host is configured on and reads the netcfg for that interface
866 """
867 import json
868 import re
869 hostsJson = json.loads( main.Cluster.active( 0 ).hosts() )
870 netcfgJson = json.loads( main.Cluster.active( 0 ).getNetCfg( subjectClass='ports') )
871 for hostname in hostList:
872 try:
873 hostComponent = main.Network.hosts[ str( hostname ) ]
874 srcIface = hostComponent.interfaces[0].get( 'name' )
875 #Get host location, check netcfg for that port's ip
876 hostIp = hostComponent.getIPAddress( iface=srcIface )
Siddeshde1d1692021-09-15 18:12:57 +0000877 if not hostIp:
878 hostIp=hostComponent.interfaces[0].get( 'ips' )[0]
Jon Hall326501b2021-08-31 10:14:55 -0700879 main.log.warn( "Looking for allowed vlans for %s" % hostIp )
880 vlans = []
881 for obj in hostsJson:
882 if hostIp in obj['ipAddresses']:
883 for location in obj['locations']:
884 did = location['elementId'].encode( 'utf-8' )
885 port = location['port'].encode( 'utf-8' )
886 m = re.search( '\((\d+)\)', port )
887 if m:
888 port = m.group(1)
889 portId = "%s/%s" % ( did, port )
890 # Lookup ip assigned to this network port
891 # Valid host vlans:
892 # None if vlan-untagged
893 # vlanid if vlan-tagged: vlanid
894 # None if vlan-native + any vlan ids from vlan-tagged
895 intf = netcfgJson[ portId ][ 'interfaces' ][0]
Siddeshde1d1692021-09-15 18:12:57 +0000896 main.log.debug( intf )
Jon Hall326501b2021-08-31 10:14:55 -0700897 for field in intf.keys():
898 if "vlan-untagged" in field:
899 vlans.append( None )
900 if "vlan-tagged" in field:
Siddeshde1d1692021-09-15 18:12:57 +0000901 for VLAN in intf[ field ]:
902 vlans.append( VLAN )
Jon Hall326501b2021-08-31 10:14:55 -0700903 if "vlan-native" in field:
904 vlans.append( None )
905 if len( vlans ) == 0:
906 main.log.debug( "Could not find vlan setting for %s" % hostname )
907 vlans = set( vlans )
Siddeshd9840842021-08-06 19:26:05 +0000908 hostComponent.interfaces[0][ 'vlan' ] = list( vlans )
Jon Hall326501b2021-08-31 10:14:55 -0700909 main.log.debug( repr( hostComponent.interfaces[0] ) )
910 main.log.debug( repr( hostComponent.interfaces[0].get( 'vlan' ) ) )
911 except ValueError:
912 main.log.exception( "Error getting vlans for %s" % hostname )
913
914
915 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700916 def killLink( main, end1, end2, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700917 """
918 end1,end2: identify the switches, ex.: 'leaf1', 'spine1'
919 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
920 Kill a link and verify ONOS can see the proper link change
921 """
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 )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700926 main.step( "Kill link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700927 linkDown = main.Network.link( END1=end1, END2=end2, OPTION="down" )
928 linkDown = linkDown and main.Network.link( END2=end1, END1=end2, OPTION="down" )
Jon Hall214f88b2020-09-21 10:21:42 -0700929 utilities.assert_equals( expect=main.TRUE, actual=linkDown,
930 onpass="Link down successful",
931 onfail="Failed to turn off link?" )
Jon Halla604fd42018-05-04 14:27:27 -0700932 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700933 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700934 "Waiting %s seconds for link down to be discovered" % sleep )
935 time.sleep( sleep )
Jon Hall214f88b2020-09-21 10:21:42 -0700936 main.step( "Checking topology after link down" )
Devin Lim142b5342017-07-20 15:22:39 -0700937 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700938 main.FALSE,
939 kwargs={ 'numoswitch': switches,
940 'numolink': links },
941 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700942 sleep=sleep )
Jon Hall214f88b2020-09-21 10:21:42 -0700943 utilities.assert_equals( expect=main.TRUE, actual=topology,
944 onpass="Topology after link down is correct",
945 onfail="Topology after link down is incorrect" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700946
947 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700948 def killLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800949 """
950 links = list of links (src, dst) to bring down.
951 """
952
953 main.step("Killing 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="down")
961 main.Network.link( END1=end2, END2=end1, OPTION="down")
962
Jon Halla604fd42018-05-04 14:27:27 -0700963 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800964 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700965 "Waiting %s seconds for links down to be discovered" % sleep )
966 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800967
968 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
969 main.FALSE,
970 kwargs={ 'numoswitch': switches,
971 'numolink': linksAfter },
972 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700973 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800974
You Wang2854bce2018-03-30 10:15:32 -0700975 utilities.assert_equals( expect=main.TRUE, actual=topology,
976 onpass="Link batch down successful",
977 onfail="Link batch down failed" )
978
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800979 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700980 def restoreLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800981 """
982 links = list of link (src, dst) to bring up again.
983 """
984
985 main.step("Restoring a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700986 if sleep is None:
987 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
988 else:
989 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800990
991 for end1, end2 in links:
992 main.Network.link( END1=end1, END2=end2, OPTION="up")
993 main.Network.link( END1=end2, END2=end1, OPTION="up")
994
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800995 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700996 "Waiting %s seconds for links up to be discovered" % sleep )
997 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800998
999 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
1000 main.FALSE,
1001 kwargs={ 'numoswitch': switches,
1002 'numolink': linksAfter },
1003 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -07001004 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -08001005
You Wang2854bce2018-03-30 10:15:32 -07001006 utilities.assert_equals( expect=main.TRUE, actual=topology,
1007 onpass="Link batch up successful",
1008 onfail="Link batch up failed" )
1009
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -08001010 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001011 def disablePortBatch( main, ports, switches=None, links=None, sleep=None ):
1012 """
1013 Disable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
1014 ports: a list of ports to disable ex. [ [ "of:0000000000000001", 1 ] ]
1015 switches, links: number of expected switches and links after link change, ex.: '4', '6'
1016 """
1017 if sleep is None:
1018 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
1019 else:
1020 sleep = float( sleep )
1021 main.step( "Disable a batch of ports" )
1022 for dpid, port in ports:
1023 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="disable" )
1024 main.log.info( "Waiting {} seconds for port down to be discovered".format( sleep ) )
1025 time.sleep( sleep )
1026 if switches and links:
1027 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
1028 numolink=links )
1029 utilities.assert_equals( expect=main.TRUE, actual=result,
1030 onpass="Port down successful",
1031 onfail="Port down failed" )
1032
1033 @staticmethod
1034 def enablePortBatch( main, ports, switches, links, sleep=None ):
1035 """
1036 Enable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
1037 ports: a list of ports to enable ex. [ [ "of:0000000000000001", 1 ] ]
1038 switches, links: number of expected switches and links after link change, ex.: '4', '6'
1039 """
1040 if sleep is None:
1041 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
1042 else:
1043 sleep = float( sleep )
1044 main.step( "Enable a batch of ports" )
1045 for dpid, port in ports:
1046 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="enable" )
1047 main.log.info( "Waiting {} seconds for port up to be discovered".format( sleep ) )
1048 time.sleep( sleep )
1049 if switches and links:
1050 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
1051 numolink=links )
1052 utilities.assert_equals( expect=main.TRUE, actual=result,
1053 onpass="Port up successful",
1054 onfail="Port up failed" )
1055
1056 @staticmethod
You Wangc02d8352018-04-17 16:42:10 -07001057 def restoreLink( main, end1, end2, switches, links,
Jon Halla604fd42018-05-04 14:27:27 -07001058 portUp=False, dpid1='', dpid2='', port1='', port2='', sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001059 """
1060 Params:
1061 end1,end2: identify the end switches, ex.: 'leaf1', 'spine1'
You Wangc02d8352018-04-17 16:42:10 -07001062 portUp: enable portstate after restoring link
Jon Hall1efcb3f2016-08-23 13:42:15 -07001063 dpid1, dpid2: dpid of the end switches respectively, ex.: 'of:0000000000000002'
1064 port1, port2: respective port of the end switches that connects to the link, ex.:'1'
1065 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
1066 Kill a link and verify ONOS can see the proper link change
1067 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001068 main.step( "Restore link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -07001069 if sleep is None:
1070 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
1071 else:
1072 sleep = float( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001073 result = False
1074 count = 0
1075 while True:
1076 count += 1
Jon Halla604fd42018-05-04 14:27:27 -07001077 ctrl = main.Cluster.next()
You Wangd5873482018-01-24 12:30:00 -08001078 main.Network.link( END1=end1, END2=end2, OPTION="up" )
1079 main.Network.link( END2=end1, END1=end2, OPTION="up" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001080 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -07001081 "Waiting %s seconds for link up to be discovered" % sleep )
1082 time.sleep( sleep )
Pierfb719b12016-09-19 14:51:44 -07001083
You Wangc02d8352018-04-17 16:42:10 -07001084 if portUp:
1085 ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
1086 ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
Jon Hall43060f62020-06-23 13:13:33 -07001087 main.log.info(
1088 "Waiting %s seconds for link up to be discovered" % sleep )
Jon Halla604fd42018-05-04 14:27:27 -07001089 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001090
Jon Halla604fd42018-05-04 14:27:27 -07001091 result = ctrl.CLI.checkStatus( numoswitch=switches,
1092 numolink=links )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001093 if count > 5 or result:
1094 break
1095 utilities.assert_equals( expect=main.TRUE, actual=result,
1096 onpass="Link up successful",
1097 onfail="Failed to bring link up" )
1098
1099 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001100 def killSwitch( main, switch, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001101 """
1102 Params: switches, links: number of expected switches and links after SwitchDown, ex.: '4', '6'
1103 Completely kill a switch and verify ONOS can see the proper change
1104 """
Jon Halla604fd42018-05-04 14:27:27 -07001105 if sleep is None:
1106 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
1107 else:
1108 sleep = float( sleep )
You Wangc02d8352018-04-17 16:42:10 -07001109 switch = switch if isinstance( switch, list ) else [ switch ]
1110 main.step( "Kill " + str( switch ) )
1111 for s in switch:
1112 main.log.info( "Stopping " + s )
1113 main.Network.switch( SW=s, OPTION="stop" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001114 # todo make this repeatable
Jon Halla604fd42018-05-04 14:27:27 -07001115
1116 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -07001117 main.log.info( "Waiting %s seconds for switch down to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -07001118 sleep ) )
1119 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -07001120 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001121 main.FALSE,
1122 kwargs={ 'numoswitch': switches,
1123 'numolink': links },
1124 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -07001125 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001126 utilities.assert_equals( expect=main.TRUE, actual=topology,
1127 onpass="Kill switch successful",
1128 onfail="Failed to kill switch?" )
1129
1130 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001131 def recoverSwitch( main, switch, switches, links, rediscoverHosts=False, hostsToDiscover=[], sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001132 """
1133 Params: switches, links: number of expected switches and links after SwitchUp, ex.: '4', '6'
1134 Recover a switch and verify ONOS can see the proper change
1135 """
Jon Halla604fd42018-05-04 14:27:27 -07001136 if sleep is None:
1137 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
1138 else:
1139 sleep = float( sleep )
1140 # TODO make this repeatable
You Wangc02d8352018-04-17 16:42:10 -07001141 switch = switch if isinstance( switch, list ) else [ switch ]
1142 main.step( "Recovering " + str( switch ) )
1143 for s in switch:
1144 main.log.info( "Starting " + s )
1145 main.Network.switch( SW=s, OPTION="start" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001146 main.log.info( "Waiting %s seconds for switch up to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -07001147 sleep ) )
1148 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -07001149 if rediscoverHosts:
You Wang48381752018-05-07 13:50:57 -07001150 main.Network.discoverHosts( hostList=hostsToDiscover )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -07001151 main.log.info( "Waiting %s seconds for hosts to get re-discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -07001152 sleep ) )
1153 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -07001154
Devin Lim142b5342017-07-20 15:22:39 -07001155 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001156 main.FALSE,
1157 kwargs={ 'numoswitch': switches,
1158 'numolink': links },
1159 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -07001160 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001161 utilities.assert_equals( expect=main.TRUE, actual=topology,
1162 onpass="Switch recovery successful",
1163 onfail="Failed to recover switch?" )
1164
Jonghwan Hyun25c98a62018-05-04 13:59:09 -07001165 @staticmethod
You Wang0f745de2018-07-27 15:49:22 -07001166 def killRouter( main, router, sleep=None ):
1167 """
1168 Kill bgpd process on a quagga router
1169 router: name of the router to be killed. E.g. "bgp1"
1170 """
1171 sleep = float( sleep )
1172 main.step( "Kill " + str( router ) )
1173 if hasattr( main, 'Mininet1' ):
1174 main.Mininet1.handle.sendline( "px {}.stopProtocols()".format( router ) )
1175 main.Mininet1.handle.expect( "mininet>" )
1176 else:
1177 # TODO: support killing router in physical network
1178 pass
1179 main.log.info( "Waiting %s seconds for router down to be discovered" % ( sleep ) )
1180 time.sleep( sleep )
1181
1182 @staticmethod
1183 def recoverRouter( main, router, sleep=None ):
1184 """
1185 Restart bgpd process on a quagga router
1186 router: name of the router to be recovered. E.g. "bgp1"
1187 """
1188 sleep = float( sleep )
1189 main.step( "Recovering " + str( router ) )
1190 if hasattr( main, 'Mininet1' ):
1191 main.Mininet1.handle.sendline( "px {}.startProtocols()".format( router ) )
1192 main.Mininet1.handle.expect( "mininet>" )
1193 else:
1194 # TODO: support recovering router in physical network
1195 pass
1196 main.log.info( "Waiting %s seconds for router up to be discovered" % ( sleep ) )
1197 time.sleep( sleep )
1198
1199 @staticmethod
You Wang5da39c82018-04-26 22:55:08 -07001200 def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001201 """
1202 Stop Onos-cluster.
1203 Stops Mininet
1204 Copies ONOS log
1205 """
You Wang4cc61912018-08-28 10:10:58 -07001206 from tests.dependencies.utils import Utils
1207 main.utils = Utils()
Jon Hall627b1572020-12-01 12:01:15 -08001208 if not main.persistentSetup:
1209 for ctrl in main.Cluster.active():
1210 ctrl.CLI.log( "\"Ending Test - Shutting down ONOS and Network\"", level="INFO" )
You Wang4cc61912018-08-28 10:10:58 -07001211 # Clean up scapy hosts
You Wange24d6272018-03-27 21:18:50 -07001212 if hasattr( main, "scapyHosts" ):
1213 scapyResult = main.TRUE
1214 for host in main.scapyHosts:
1215 scapyResult = host.stopScapy() and scapyResult
1216 main.log.info( "Stopped Scapy Host: {0}".format( host.name ) )
1217 for host in main.scapyHosts:
You Wang4cc61912018-08-28 10:10:58 -07001218 if hasattr( main, 'Mininet1' ):
1219 scapyResult = main.Scapy.removeHostComponent( host.name ) and scapyResult
1220 else:
1221 scapyResult = main.Network.removeHostComponent( host.name ) and scapyResult
You Wange24d6272018-03-27 21:18:50 -07001222 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
1223 main.scapyHosts = []
1224
You Wang5da39c82018-04-26 22:55:08 -07001225 if removeHostComponent:
Jon Hall22a3bcf2021-07-23 11:40:11 -07001226 try:
1227 for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
1228 if hasattr( main, host ):
1229 if hasattr( main, 'Mininet1' ):
1230 pass
1231 else:
1232 getattr( main, host ).disconnectInband()
1233 main.Network.removeHostComponent( host )
1234 except AttributeError as e:
1235 main.log.warn( "Could not cleanup host components: " + repr( e ) )
You Wang5da39c82018-04-26 22:55:08 -07001236
You Wang5df1c6d2018-04-06 18:02:02 -07001237 if hasattr( main, 'Mininet1' ):
Pier6a0c4de2018-03-18 16:01:30 -07001238 main.utils.mininetCleanup( main.Mininet1 )
You Wang4cc61912018-08-28 10:10:58 -07001239 else:
1240 main.Network.disconnectInbandHosts()
1241 main.Network.disconnectFromNet()
Devin Lim58046fa2017-07-05 16:55:00 -07001242
You Wang5df1c6d2018-04-06 18:02:02 -07001243 if copyKarafLog:
1244 main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=True, includeCaseDesc=False )
Devin Lim58046fa2017-07-05 16:55:00 -07001245
Jon Hall627b1572020-12-01 12:01:15 -08001246 if not main.persistentSetup:
1247 for ctrl in main.Cluster.active():
1248 main.ONOSbench.onosStop( ctrl.ipAddress )
Jon Hall06fd0df2021-01-25 15:50:06 -08001249 else:
1250 Testcaselib.resetOnosLogLevels( main )
Jon Hall43060f62020-06-23 13:13:33 -07001251 Testcaselib.mnDockerTeardown( main )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001252
1253 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001254 def verifyNodes( main ):
1255 """
1256 Verifies Each active node in the cluster has an accurate view of other node's and their status
1257
1258 Params:
1259 nodes, integer array with position of the ONOS nodes in the CLIs array
1260 """
1261 nodeResults = utilities.retry( main.Cluster.nodesCheck,
1262 False,
1263 attempts=10,
1264 sleep=10 )
1265 utilities.assert_equals( expect=True, actual=nodeResults,
1266 onpass="Nodes check successful",
1267 onfail="Nodes check NOT successful" )
1268
1269 if not nodeResults:
1270 for ctrl in main.Cluster.runningNodes:
1271 main.log.debug( "{} components not ACTIVE: \n{}".format(
1272 ctrl.name,
Jon Hall6c9e2da2018-11-06 12:01:23 -08001273 ctrl.CLI.sendline( "onos:scr-list | grep -v ACTIVE" ) ) )
You Wang0bed5932018-12-11 14:45:41 -08001274 main.log.error( "Failed to verify nodes, stopping test" )
Jon Halla604fd42018-05-04 14:27:27 -07001275 main.cleanAndExit()
1276
1277 @staticmethod
Jon Hall39570262020-11-17 12:18:19 -08001278 def verifyTopology( main, switches, links, expNodes, SCCs=1 ):
Jon Halla604fd42018-05-04 14:27:27 -07001279 """
1280 Verifies that the ONOS cluster has an acuurate view of the topology
1281
1282 Params:
1283 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 -08001284 SCCs = Number of connected topology clusters within the control plane, defaults to 1
Jon Halla604fd42018-05-04 14:27:27 -07001285 """
1286 main.step( "Check number of topology elements" )
1287 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
1288 main.FALSE,
1289 kwargs={ 'numoswitch': switches,
1290 'numolink': links,
Jon Hall39570262020-11-17 12:18:19 -08001291 'numoctrl': expNodes,
1292 'numoSCCs': SCCs },
Jon Halla604fd42018-05-04 14:27:27 -07001293 attempts=10,
1294 sleep=12 )
1295 utilities.assert_equals( expect=main.TRUE, actual=topology,
1296 onpass="Number of topology elements are correct",
Jon Hall39570262020-11-17 12:18:19 -08001297 onfail="Unexpected number of links, switches, and/or controllers: " + main.TOPOOUTPUT )
Jon Halla604fd42018-05-04 14:27:27 -07001298
1299 @staticmethod
1300 def killOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001301 """
1302 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1303 switches, links, nodes: number of expected switches, links and nodes after KillOnos, ex.: '4', '6'
1304 Completely Kill an ONOS instance and verify the ONOS cluster can see the proper change
1305 """
Jon Halla604fd42018-05-04 14:27:27 -07001306 # TODO: We have enough information in the Cluster instance to remove expNodes from here and verifyTopology
Jon Hall3c910162018-03-07 14:42:16 -08001307 main.step( "Killing ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001308 if sleep is None:
1309 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1310 else:
1311 sleep = float( sleep )
Pier3b58c652016-09-26 12:03:31 -07001312
Jon Hall214f88b2020-09-21 10:21:42 -07001313 stepResult = main.TRUE
Jon Hall1efcb3f2016-08-23 13:42:15 -07001314 for i in nodes:
Jon Hall214f88b2020-09-21 10:21:42 -07001315 node = main.Cluster.runningNodes[ i ]
1316 if node.inDocker:
1317 killResult = node.server.dockerStop( node.name )
1318 else:
1319 killResult = main.ONOSbench.onosDie( node.ipAddress )
1320 stepResult = stepResult and killResult
Devin Lim142b5342017-07-20 15:22:39 -07001321 main.Cluster.runningNodes[ i ].active = False
Jon Hall214f88b2020-09-21 10:21:42 -07001322 utilities.assert_equals( expect=main.TRUE, actual=stepResult,
1323 onpass="ONOS instance Killed",
1324 onfail="Error killing ONOS instance" )
Jon Halla604fd42018-05-04 14:27:27 -07001325 main.Cluster.reset()
Jon Hall43060f62020-06-23 13:13:33 -07001326 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001327 time.sleep( sleep )
Pier3b58c652016-09-26 12:03:31 -07001328
Devin Lim142b5342017-07-20 15:22:39 -07001329 if len( nodes ) < main.Cluster.numCtrls:
Jon Halla604fd42018-05-04 14:27:27 -07001330 Testcaselib.verifyNodes( main )
1331 Testcaselib.verifyTopology( main, switches, links, expNodes )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001332
1333 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001334 def recoverOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001335 """
1336 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1337 switches, links, nodes: number of expected switches, links and nodes after recoverOnos, ex.: '4', '6'
1338 Recover an ONOS instance and verify the ONOS cluster can see the proper change
1339 """
Jon Hall3c910162018-03-07 14:42:16 -08001340 main.step( "Recovering ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001341 if sleep is None:
1342 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1343 else:
1344 sleep = float( sleep )
Jon Hall214f88b2020-09-21 10:21:42 -07001345 for i in nodes:
1346 node = main.Cluster.runningNodes[ i ]
1347 if node.inDocker:
1348 main.Cluster.startONOSDockerNode( i )
1349 else:
1350 main.ONOSbench.onosStart( node.ipAddress )
Jon Hall43060f62020-06-23 13:13:33 -07001351 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001352 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001353 for i in nodes:
Jon Hall39570262020-11-17 12:18:19 -08001354 node = main.Cluster.runningNodes[ i ]
Jon Hall214f88b2020-09-21 10:21:42 -07001355 if node.inDocker:
1356 isUp = node.CLI.dockerExec( node.name, dockerPrompt=node.dockerPrompt )
1357 isUp = isUp and node.CLI.prepareForCLI()
1358 isUp = isUp and node.CLI.onosSecureSSH( userName=node.karafUser, userPWD=node.karafPass )
1359 else:
1360 isUp = main.ONOSbench.isup( node.ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001361 utilities.assert_equals( expect=main.TRUE, actual=isUp,
1362 onpass="ONOS service is ready",
1363 onfail="ONOS service did not start properly" )
1364 for i in nodes:
1365 main.step( "Checking if ONOS CLI is ready" )
Devin Lim142b5342017-07-20 15:22:39 -07001366 ctrl = main.Cluster.runningNodes[ i ]
Jonghwan Hyun76a02b72018-01-30 16:40:48 +09001367 # ctrl.CLI.startCellCli()
Devin Lim142b5342017-07-20 15:22:39 -07001368 cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
1369 commandlineTimeout=60,
1370 onosStartTimeout=100 )
1371 ctrl.active = True
Jon Hall1efcb3f2016-08-23 13:42:15 -07001372 utilities.assert_equals( expect=main.TRUE,
1373 actual=cliResult,
1374 onpass="ONOS CLI is ready",
1375 onfail="ONOS CLI is not ready" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001376
Jon Halla604fd42018-05-04 14:27:27 -07001377 main.Cluster.reset()
Pier3b58c652016-09-26 12:03:31 -07001378 main.step( "Checking ONOS nodes" )
Jon Halla604fd42018-05-04 14:27:27 -07001379 Testcaselib.verifyNodes( main )
1380 Testcaselib.verifyTopology( main, switches, links, expNodes )
Pier3b58c652016-09-26 12:03:31 -07001381
Devin Lim142b5342017-07-20 15:22:39 -07001382 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -07001383 [ None, main.FALSE ],
Devin Lim142b5342017-07-20 15:22:39 -07001384 attempts=10,
1385 sleep=12 )
1386 if ready:
1387 ready = main.TRUE
1388 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001389 onpass="ONOS summary command succeded",
1390 onfail="ONOS summary command failed" )
1391 if not ready:
1392 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -07001393 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -07001394
1395 @staticmethod
1396 def addHostCfg( main ):
1397 """
1398 Adds Host Configuration to ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001399 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001400 """
1401 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001402 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001403 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001404 hostCfg = json.load( template )
1405 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
1406 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001407 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001408 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1409 subjectClass="hosts",
1410 subjectKey=urllib.quote( mac,
1411 safe='' ),
1412 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001413 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
1414 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001415 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001416 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1417 subjectClass="hosts",
1418 subjectKey=urllib.quote( mac,
1419 safe='' ),
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001420 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001421 main.pingChart.update( { 'vlan1': { "expect": "True",
1422 "hosts": [ "olt1", "vsg1" ] } } )
1423 main.pingChart[ 'vlan5' ][ 'expect' ] = 0
1424 main.pingChart[ 'vlan10' ][ 'expect' ] = 0
Jon Hall10e2ab82020-09-15 17:14:54 -07001425 main.Cluster.active( 0 ).REST.setXconnect( "of:0000000000000001",
1426 vlanId=1,
1427 port1=5,
1428 port2=6 )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001429
1430 @staticmethod
1431 def delHostCfg( main ):
1432 """
1433 Removest Host Configuration from ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001434 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001435 """
1436 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001437 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001438 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001439 hostCfg = json.load( template )
1440 main.step( "Removing host configuration" )
1441 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001442 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001443 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1444 subjectKey=urllib.quote(
1445 mac,
1446 safe='' ),
1447 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001448 main.step( "Removing configuration" )
1449 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001450 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001451 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1452 subjectKey=urllib.quote(
1453 mac,
1454 safe='' ),
1455 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001456 main.step( "Removing vlan configuration" )
1457 main.pingChart[ 'vlan1' ][ 'expect' ] = 0
Jon Hall10e2ab82020-09-15 17:14:54 -07001458 main.Cluster.active( 0 ).REST.deleteXconnect( "of:0000000000000001",
1459 vlanId=1 )
You Wang53dba1e2018-02-02 17:45:44 -08001460
1461 @staticmethod
1462 def verifyNetworkHostIp( main, attempts=10, sleep=10 ):
1463 """
1464 Verifies IP address assignment from the hosts
1465 """
1466 main.step( "Verify IP address assignment from hosts" )
1467 ipResult = main.TRUE
You Wangd66de192018-04-30 17:30:12 -07001468 main.Network.update()
You Wang6acb7a42018-05-04 15:12:25 -07001469 # Find out names of disconnected hosts
1470 disconnectedHosts = []
1471 if hasattr( main, "disconnectedIpv4Hosts" ):
1472 for host in main.disconnectedIpv4Hosts:
1473 disconnectedHosts.append( host )
1474 if hasattr( main, "disconnectedIpv6Hosts" ):
1475 for host in main.disconnectedIpv6Hosts:
1476 disconnectedHosts.append( host )
You Wang53dba1e2018-02-02 17:45:44 -08001477 for hostName, ip in main.expectedHosts[ "network" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001478 # Exclude disconnected hosts
1479 if hostName in disconnectedHosts:
1480 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( hostName ) )
1481 continue
You Wang53dba1e2018-02-02 17:45:44 -08001482 ipResult = ipResult and utilities.retry( main.Network.verifyHostIp,
1483 main.FALSE,
1484 kwargs={ 'hostList': [ hostName ],
You Wangd66de192018-04-30 17:30:12 -07001485 'prefix': ip,
Jon Hall43060f62020-06-23 13:13:33 -07001486 'update': True },
You Wang53dba1e2018-02-02 17:45:44 -08001487 attempts=attempts,
1488 sleep=sleep )
1489 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1490 onpass="Verify network host IP succeded",
1491 onfail="Verify network host IP failed" )
1492
1493 @staticmethod
You Wangaec6a092018-08-06 15:36:31 -07001494 def verifyOnosHostIp( main, attempts=10, sleep=10, skipOnFail=True ):
You Wang53dba1e2018-02-02 17:45:44 -08001495 """
1496 Verifies host IP address assignment from ONOS
1497 """
1498 main.step( "Verify host IP address assignment in ONOS" )
1499 ipResult = main.TRUE
You Wang6acb7a42018-05-04 15:12:25 -07001500 # Find out IPs of disconnected hosts
1501 disconnectedIps = []
1502 if hasattr( main, "disconnectedIpv4Hosts" ):
1503 for host in main.disconnectedIpv4Hosts:
1504 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
1505 if hasattr( main, "disconnectedIpv6Hosts" ):
1506 for host in main.disconnectedIpv6Hosts:
1507 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
You Wang53dba1e2018-02-02 17:45:44 -08001508 for hostName, ip in main.expectedHosts[ "onos" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001509 # Exclude disconnected hosts
1510 if ip in disconnectedIps:
1511 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( ip ) )
1512 continue
You Wang53dba1e2018-02-02 17:45:44 -08001513 ipResult = ipResult and utilities.retry( main.Cluster.active( 0 ).verifyHostIp,
1514 main.FALSE,
1515 kwargs={ 'hostList': [ hostName ],
1516 'prefix': ip },
1517 attempts=attempts,
1518 sleep=sleep )
1519 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1520 onpass="Verify ONOS host IP succeded",
1521 onfail="Verify ONOS host IP failed" )
You Wangaec6a092018-08-06 15:36:31 -07001522 if not ipResult and skipOnFail:
1523 Testcaselib.saveOnosDiagnostics( main )
You Wang89477152018-08-07 14:19:02 -07001524 Testcaselib.cleanup( main, copyKarafLog=False )
You Wangaec6a092018-08-06 15:36:31 -07001525 main.skipCase()
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -08001526
Jonghwan Hyun812c70f2018-02-16 16:33:16 -08001527 @staticmethod
1528 def updateIntfCfg( main, connectPoint, ips=[], untagged=0, tagged=[], native=0 ):
1529 """
1530 Description:
1531 Updates interface configuration in ONOS, with given IP and vlan parameters
1532 Required:
1533 * connectPoint: connect point to update configuration
1534 Optional:
1535 * ips: list of IP addresses, combined with '/xx' subnet representation,
1536 corresponding to 'ips' field in the configuration
1537 * untagged: vlan ID as an integer, corresponding to 'vlan-untagged' field in the configuration
1538 * tagged: integer list of vlan IDs, corresponding to 'vlan-tagged' field in the configuration
1539 * native: vlan ID as an integer, corresponding to 'vlan-native' field in the configuration
1540 """
1541 cfg = dict()
1542 cfg[ "ports" ] = dict()
1543 cfg[ "ports" ][ connectPoint ] = dict()
1544 cfg[ "ports" ][ connectPoint ][ "interfaces" ] = [ dict() ]
1545 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "ips" ] = ips
1546 if untagged > 0:
1547 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-untagged" ] = untagged
1548 else:
1549 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-tagged" ] = tagged
1550 if native > 0:
1551 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-native" ] = native
1552
1553 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( json.dumps( cfg ) ) )
You Wange24d6272018-03-27 21:18:50 -07001554
1555 @staticmethod
You Wang2cb70172018-07-25 16:44:13 -07001556 def startScapyHosts( main, scapyNames=[], mininetNames=[] ):
You Wange24d6272018-03-27 21:18:50 -07001557 """
1558 Create host components and start Scapy CLIs
You Wang2cb70172018-07-25 16:44:13 -07001559 scapyNames: list of names that will be used as component names for scapy hosts
1560 mininetNames: used when scapy host names are different from the host names
1561 in Mininet. E.g. when scapyNames=['h1Scapy'], it's required to specify the
1562 name of the corresponding Mininet host by mininetNames=['h1']
You Wange24d6272018-03-27 21:18:50 -07001563 """
1564 main.step( "Start Scapy CLIs" )
You Wang4cc61912018-08-28 10:10:58 -07001565 main.scapyNames = scapyNames if scapyNames else main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
1566 main.scapyHosts = [] if not hasattr( main, "scapyHosts" ) else main.scapyHosts
You Wang2cb70172018-07-25 16:44:13 -07001567 for scapyName in main.scapyNames:
You Wang4cc61912018-08-28 10:10:58 -07001568 if hasattr( main, 'Mininet1' ):
1569 main.Scapy.createHostComponent( scapyName )
1570 scapyHandle = getattr( main, scapyName )
1571 if mininetNames:
1572 mininetName = mininetNames[ scapyNames.index( scapyName ) ]
1573 else:
1574 mininetName = None
Jon Hall43060f62020-06-23 13:13:33 -07001575 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
1576 scapyHandle.mExecDir = "/tmp"
1577 scapyHandle.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1578 main.log.debug( "start mn host component in docker" )
1579 scapyHandle.startHostCli( mininetName,
1580 execDir="/tmp",
1581 hostHome=main.params[ "MN_DOCKER" ][ "home" ] )
1582 else:
1583 main.log.debug( "start mn host component" )
1584 scapyHandle.startHostCli( mininetName )
You Wang2cb70172018-07-25 16:44:13 -07001585 else:
You Wang0fc21702018-11-02 17:49:18 -07001586 main.Network.createHostComponent( scapyName )
You Wang4cc61912018-08-28 10:10:58 -07001587 scapyHandle = getattr( main, scapyName )
1588 scapyHandle.connectInband()
1589 main.scapyHosts.append( scapyHandle )
You Wang2cb70172018-07-25 16:44:13 -07001590 scapyHandle.startScapy()
1591 scapyHandle.updateSelf()
1592 main.log.debug( scapyHandle.name )
1593 main.log.debug( scapyHandle.hostIp )
1594 main.log.debug( scapyHandle.hostMac )
1595
1596 @staticmethod
1597 def verifyTraffic( main, srcHosts, dstIp, dstHost, dstIntf, ipv6=False, expect=True, skipOnFail=True, maxRetry=2 ):
1598 """
1599 Verify unicast traffic by pinging from source hosts to the destination IP
1600 and capturing the packets at the destination host using Scapy.
1601 srcHosts: List of host names to send the ping packets
1602 dstIp: destination IP of the ping packets
1603 dstHost: host that runs Scapy to capture the packets
1604 dstIntf: name of the interface on the destination host
1605 expect: use True if the ping is expected to be captured at destination;
1606 Otherwise False
1607 skipOnFail: skip the rest of this test case if result is not expected
1608 maxRetry: number of retries allowed
1609 """
1610 from tests.dependencies.topology import Topology
1611 try:
1612 main.topo
1613 except ( NameError, AttributeError ):
1614 main.topo = Topology()
1615 main.step( "Verify traffic to {} by capturing packets on {}".format( dstIp, dstHost ) )
1616 result = main.TRUE
1617 for srcHost in srcHosts:
1618 trafficResult = main.topo.pingAndCapture( srcHost, dstIp, dstHost, dstIntf, ipv6,
1619 expect, maxRetry, True )
1620 if not trafficResult:
You Wang2cb70172018-07-25 16:44:13 -07001621 result = main.FALSE
1622 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcHost, dstIp ) )
1623 utilities.assert_equals( expect=main.TRUE,
1624 actual=result,
1625 onpass="Verify traffic to {}: Pass".format( dstIp ),
1626 onfail="Verify traffic to {}: Fail".format( dstIp ) )
1627 if skipOnFail and result != main.TRUE:
1628 Testcaselib.saveOnosDiagnostics( main )
1629 Testcaselib.cleanup( main, copyKarafLog=False )
1630 main.skipCase()
You Wange24d6272018-03-27 21:18:50 -07001631
1632 @staticmethod
You Wang547893e2018-05-08 13:34:59 -07001633 def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=1 ):
You Wange24d6272018-03-27 21:18:50 -07001634 """
1635 Verify multicast traffic using scapy
1636 """
You Wangc564c6f2018-05-01 15:24:57 -07001637 from tests.dependencies.topology import Topology
1638 try:
1639 main.topo
1640 except ( NameError, AttributeError ):
1641 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001642 main.step( "Verify {} multicast traffic".format( routeName ) )
You Wangc02d8352018-04-17 16:42:10 -07001643 routeData = main.multicastConfig[ routeName ]
1644 srcs = main.mcastRoutes[ routeName ][ "src" ]
1645 dsts = main.mcastRoutes[ routeName ][ "dst" ]
1646 main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
1647 [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
You Wang85747762018-05-11 15:51:50 -07001648 result = main.TRUE
You Wangc02d8352018-04-17 16:42:10 -07001649 for src in srcs:
1650 srcEntry = routeData[ "src" ][ src ]
1651 for dst in dsts:
1652 dstEntry = routeData[ "dst" ][ dst ]
1653 sender = getattr( main, srcEntry[ "host" ] )
1654 receiver = getattr( main, dstEntry[ "host" ] )
1655 main.Network.addRoute( str( srcEntry[ "host" ] ),
1656 str( routeData[ "group" ] ),
1657 str( srcEntry[ "interface" ] ),
1658 True if routeData[ "ipVersion" ] == 6 else False )
1659 # Build the packet
1660 sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
1661 if routeData[ "ipVersion" ] == 4:
1662 sender.buildIP( dst=str( routeData[ "group" ] ) )
1663 elif routeData[ "ipVersion" ] == 6:
1664 sender.buildIPv6( dst=str( routeData[ "group" ] ) )
1665 sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
1666 sIface = srcEntry[ "interface" ]
1667 dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
1668 pktFilter = srcEntry[ "filter" ]
1669 pkt = srcEntry[ "packet" ]
1670 # Send packet and check received packet
1671 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
You Wangc564c6f2018-05-01 15:24:57 -07001672 t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
Jon Halla604fd42018-05-04 14:27:27 -07001673 routeData[ "group" ], srcEntry[ "Ether" ] )
You Wangc564c6f2018-05-01 15:24:57 -07001674 trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
1675 expectedResult, maxRetry, True, t3Cmd )
You Wang85747762018-05-11 15:51:50 -07001676 if not trafficResult:
1677 result = main.FALSE
1678 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcEntry[ "host" ],
1679 dstEntry[ "host" ] ) )
1680 utilities.assert_equals( expect=main.TRUE,
1681 actual=result,
1682 onpass="Verify {} multicast traffic: Pass".format( routeName ),
1683 onfail="Verify {} multicast traffic: Fail".format( routeName ) )
You Wangba823f02018-05-17 13:54:08 -07001684 if skipOnFail and result != main.TRUE:
You Wang85747762018-05-11 15:51:50 -07001685 Testcaselib.saveOnosDiagnostics( main )
1686 Testcaselib.cleanup( main, copyKarafLog=False )
1687 main.skipCase()
You Wangc02d8352018-04-17 16:42:10 -07001688
1689 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001690 def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1,
You Wang54b1d672018-06-11 16:44:13 -07001691 acceptableFailed=0, skipOnFail=True, stepMsg="Verify Ping",
1692 t3Simple=True ):
You Wang5da39c82018-04-26 22:55:08 -07001693 """
1694 Verify reachability from each host in srcList to each host in dstList
1695 """
1696 from tests.dependencies.topology import Topology
1697 try:
1698 main.topo
1699 except ( NameError, AttributeError ):
1700 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001701 main.step( stepMsg )
You Wang54b1d672018-06-11 16:44:13 -07001702 pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail, t3Simple )
You Wang85747762018-05-11 15:51:50 -07001703 utilities.assert_equals( expect=main.TRUE,
1704 actual=pingResult,
1705 onpass="{}: Pass".format( stepMsg ),
1706 onfail="{}: Fail".format( stepMsg ) )
You Wang5da39c82018-04-26 22:55:08 -07001707 if not pingResult and skipOnFail:
1708 Testcaselib.saveOnosDiagnostics( main )
1709 Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
1710 main.skipCase()
You Wangbc898b82018-05-03 16:22:34 -07001711
1712 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001713 def verifyHostLocations( main, locationDict, retry=2 ):
You Wangbc898b82018-05-03 16:22:34 -07001714 """
1715 Verify if the specified host is discovered by ONOS on the given locations
1716 Required:
You Wang85747762018-05-11 15:51:50 -07001717 locationDict: a dictionary that maps host names to expected locations.
1718 locations could be a string or a list.
1719 ex. { "h1v4": ["of:0000000000000005/8"] }
You Wangbc898b82018-05-03 16:22:34 -07001720 Returns:
1721 main.TRUE if host is discovered on all locations provided, otherwise main.FALSE
1722 """
You Wang85747762018-05-11 15:51:50 -07001723 main.step( "Verify locations of hosts {}".format( locationDict.keys() ) )
1724 result = main.TRUE
1725 for hostName, locations in locationDict.items():
1726 main.log.info( "Verify host {} is discovered at {}".format( hostName, locations ) )
1727 hostIp = main.Network.getIPAddress( hostName, proto='IPV4' )
1728 if not hostIp:
1729 hostIp = main.Network.getIPAddress( hostName, proto='IPV6' )
1730 if not hostIp:
1731 main.log.warn( "Failed to find IP address for host {}, skipping location verification".format( hostName ) )
1732 result = main.FALSE
1733 continue
1734 locationResult = utilities.retry( main.Cluster.active( 0 ).CLI.verifyHostLocation,
1735 main.FALSE,
1736 args=( hostIp, locations ),
1737 attempts=retry + 1,
1738 sleep=10 )
1739 if not locationResult:
1740 result = main.FALSE
1741 main.log.warn( "location verification for host {} failed".format( hostName ) )
You Wang547893e2018-05-08 13:34:59 -07001742 utilities.assert_equals( expect=main.TRUE, actual=result,
You Wang85747762018-05-11 15:51:50 -07001743 onpass="Location verification passed",
1744 onfail="Location verification failed" )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001745
1746 @staticmethod
You Wang6e5b48e2018-07-23 16:17:38 -07001747 def moveHost( main, hostName, srcSw, dstSw, gw, macAddr=None, prefixLen=None, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001748 """
1749 Move specified host from srcSw to dstSw.
1750 If srcSw and dstSw are same, the host will be moved from current port to
1751 next available port.
1752 Required:
1753 hostName: name of the host. e.g., "h1"
1754 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1755 dstSw: name of the switch that the host will be moved to. e.g., "leaf2"
1756 gw: ip address of the gateway of the new location
1757 Optional:
1758 macAddr: if specified, change MAC address of the host to the specified MAC address.
1759 prefixLen: prefix length
1760 cfg: port configuration as JSON string
1761 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001762 vlan: vlan number of the host
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001763 """
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001764 if not hasattr( main, 'Mininet1' ):
1765 main.log.warn( "moveHost is supposed to be used only in Mininet." )
1766 return
1767
You Wang6e5b48e2018-07-23 16:17:38 -07001768 main.step( "Moving {} host {} from {} to {}".format( 'tagged' if vlan else 'untagged', hostName, srcSw, dstSw ) )
1769 main.Mininet1.moveHost( hostName, srcSw, dstSw, macAddr, prefixLen, ipv6, vlan=vlan )
1770 if not ipv6:
You Wang6260ed52018-07-18 17:54:25 -07001771 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001772 if cfg:
1773 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1774 subjectClass="ports" )
You Wang6260ed52018-07-18 17:54:25 -07001775 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001776 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang6260ed52018-07-18 17:54:25 -07001777 time.sleep( 5 )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001778
1779 main.Mininet1.discoverHosts( [ hostName, ] )
1780
1781 # Update expectedHost when MAC address is changed.
1782 if macAddr is not None:
1783 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1784 if ipAddr is not None:
1785 for hostName, ip in main.expectedHosts[ "onos" ].items():
1786 if ip == ipAddr:
1787 vlan = hostName.split( "/" )[ -1 ]
1788 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001789 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001790 break
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001791
1792 @staticmethod
1793 def moveDualHomedHost( main, hostName, srcSw, srcPairSw, dstSw, dstPairSw, gw,
You Wang6e5b48e2018-07-23 16:17:38 -07001794 macAddr=None, prefixLen=24, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001795 """
1796 Move specified dual-homed host from srcSw-srcPairSw to dstSw-dstPairSw.
1797 If srcSw-srcPairSw and dstSw-dstPairSw are same, the host will be moved from current port
1798 to next available port.
1799 Required:
1800 hostName: name of the host. e.g., "h1"
1801 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1802 srcPairSw: name of the paired-switch that the host is attached to. e.g., "leaf2"
1803 dstSw: name of the switch that the host will be moved to. e.g., "leaf1"
1804 dstPairSw: name of the paired-switch that the host will be moved to. e.g., "leaf2"
1805 gw: ip address of the gateway of the new location
1806 Optional:
1807 macAddr: if specified, change MAC address of the host to the specified MAC address.
1808 prefixLen: prefix length
1809 cfg: port configurations as JSON string
You Wang7ea90582018-07-19 15:27:58 -07001810 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001811 vlan: vlan number of the host
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001812 """
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001813 if not hasattr( main, 'Mininet1' ):
1814 main.log.warn( "moveDualHomedHost is supposed to be used only in Mininet." )
1815 return
1816
You Wang6e5b48e2018-07-23 16:17:38 -07001817 main.step( "Moving {} host {} from {} and {} to {} and {}".format( 'tagged' if vlan else 'untagged', hostName,
1818 srcSw, srcPairSw, dstSw, dstPairSw ) )
1819 main.Mininet1.moveDualHomedHost( hostName, srcSw, srcPairSw, dstSw, dstPairSw,
1820 macAddr=macAddr, prefixLen=prefixLen, ipv6=ipv6, vlan=vlan )
1821 if not ipv6:
You Wang7ea90582018-07-19 15:27:58 -07001822 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001823 if cfg:
1824 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1825 subjectClass="ports" )
You Wang7ea90582018-07-19 15:27:58 -07001826 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001827 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang7ea90582018-07-19 15:27:58 -07001828 time.sleep( 5 )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001829
1830 main.Mininet1.discoverHosts( [ hostName, ] )
1831
1832 # Update expectedHost when MAC address is changed.
1833 if macAddr is not None:
1834 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1835 if ipAddr is not None:
1836 for hostName, ip in main.expectedHosts[ "onos" ].items():
1837 if ip == ipAddr:
1838 vlan = hostName.split( "/" )[ -1 ]
1839 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001840 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jon Hall43060f62020-06-23 13:13:33 -07001841
1842 @staticmethod
1843 def mnDockerSetup( main ):
1844 """
1845 Optionally start and setup docker image for mininet
1846 """
Jon Hall9b0de1f2020-08-24 15:38:04 -07001847 try:
1848 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall43060f62020-06-23 13:13:33 -07001849
Jon Hall9b0de1f2020-08-24 15:38:04 -07001850 main.log.info( "Creating Mininet Docker" )
1851 handle = main.Mininet1.handle
1852 # build docker image
1853 dockerFilePath = "%s/../dependencies/" % main.testDir
1854 dockerName = "trellis_mininet"
1855 # Stop any leftover container
1856 main.Mininet1.dockerStop( dockerName )
1857 # TODO: assert on these docker calls
Jon Hall39570262020-11-17 12:18:19 -08001858 main.Mininet1.dockerBuild( dockerFilePath, dockerName, pull=True )
Jon Hallf6aeda22020-07-28 09:12:56 -07001859
Jon Hall9b0de1f2020-08-24 15:38:04 -07001860 confDir = "/tmp/mn_conf/"
1861 # Try to ensure the destination exists
1862 main.log.info( "Create folder for network config files" )
1863 handle.sendline( "rm -rf %s" % confDir )
1864 handle.expect( main.Mininet1.Prompt() )
1865 main.log.debug( handle.before + handle.after )
1866 handle.sendline( "mkdir -p %s" % confDir )
1867 handle.expect( main.Mininet1.Prompt() )
1868 main.log.debug( handle.before + handle.after )
Jon Hall39570262020-11-17 12:18:19 -08001869 handle.sendline( "sudo rm -rf /tmp/mn-stratum/*" )
1870 handle.expect( main.Mininet1.Prompt() )
Jon Hall9b0de1f2020-08-24 15:38:04 -07001871 # Make sure permissions are correct
1872 handle.sendline( "sudo chown %s:%s %s" % ( main.Mininet1.user_name, main.Mininet1.user_name, confDir ) )
1873 handle.expect( main.Mininet1.Prompt() )
1874 handle.sendline( "sudo chmod -R a+rwx %s" % ( confDir ) )
1875 handle.expect( main.Mininet1.Prompt() )
1876 main.log.debug( handle.before + handle.after )
1877 # Start docker container
1878 runResponse = main.Mininet1.dockerRun( main.params[ 'MN_DOCKER' ][ 'name' ],
1879 dockerName,
1880 main.params[ 'MN_DOCKER' ][ 'args' ] )
1881 if runResponse == main.FALSE:
1882 main.log.error( "Docker container already running, aborting test" )
1883 main.cleanup()
1884 main.exit()
Jon Hall43060f62020-06-23 13:13:33 -07001885
Jon Hall9b0de1f2020-08-24 15:38:04 -07001886 main.Mininet1.dockerAttach( dockerName, dockerPrompt='~#' )
1887 main.Mininet1.sudoRequired = False
Jon Hall43060f62020-06-23 13:13:33 -07001888
Jon Hall9b0de1f2020-08-24 15:38:04 -07001889 # Fow when we create component handles
1890 main.Mininet1.mExecDir = "/tmp"
1891 main.Mininet1.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1892 main.Mininet1.hostPrompt = "/home/root#"
1893
1894 # For some reason docker isn't doing this
1895 main.Mininet1.handle.sendline( "echo \"127.0.0.1 $(cat /etc/hostname)\" >> /etc/hosts" )
1896 main.Mininet1.handle.expect( "etc/hosts" )
1897 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
1898 except Exception as e:
1899 main.log.exception( "Error seting up mininet" )
Jon Hall39570262020-11-17 12:18:19 -08001900 main.skipCase( result="FAIL", msg=e )
Jon Hall43060f62020-06-23 13:13:33 -07001901
1902 @staticmethod
1903 def mnDockerTeardown( main ):
1904 """
1905 Optionally stop and cleanup docker image for mininet
1906 """
1907
1908 if hasattr( main, 'Mininet1' ):
1909 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall3c0114c2020-08-11 15:07:42 -07001910 main.log.info( "Exiting from Mininet Docker" )
Jon Hall43060f62020-06-23 13:13:33 -07001911
1912 # Detach from container
Jon Hall43060f62020-06-23 13:13:33 -07001913 try:
Jon Hall3c0114c2020-08-11 15:07:42 -07001914 main.Mininet1.dockerDisconnect()
Jon Hall43060f62020-06-23 13:13:33 -07001915 main.Mininet1.sudoRequired = True
1916 except Exception as e:
1917 main.log.error( e )
1918
Jon Hall39570262020-11-17 12:18:19 -08001919 # Save docker logs
1920 copyResult = main.ONOSbench.scp( main.Mininet1,
1921 "/tmp/mn-stratum/*",
1922 main.logdir,
1923 direction="from",
1924 options="-rp" )
1925
1926
Jon Hall43060f62020-06-23 13:13:33 -07001927 @staticmethod
1928 def setOnosConfig( main ):
1929 """
1930 Read and Set onos configurations from the params file
1931 """
1932 main.step( "Set ONOS configurations" )
1933 config = main.params.get( 'ONOS_Configuration' )
1934 if config:
1935 main.log.debug( config )
1936 checkResult = main.TRUE
1937 for component in config:
1938 for setting in config[ component ]:
1939 value = config[ component ][ setting ]
1940 check = main.Cluster.next().setCfg( component, setting, value )
1941 main.log.info( "Value was changed? {}".format( main.TRUE == check ) )
1942 checkResult = check and checkResult
1943 utilities.assert_equals( expect=main.TRUE,
1944 actual=checkResult,
1945 onpass="Successfully set config",
1946 onfail="Failed to set config" )
1947 else:
1948 main.log.warn( "No configurations were specified to be changed after startup" )
1949
1950 @staticmethod
1951 def setOnosLogLevels( main ):
1952 """
1953 Read and Set onos log levels from the params file
1954 """
1955 main.step( 'Set logging levels' )
Jon Hall06fd0df2021-01-25 15:50:06 -08001956 # Get original values incase we want to reset them
1957 ctrl = main.Cluster.active(0)
Jon Halla7b27e62021-06-29 12:13:51 -07001958 ctrl.CLI.clearBuffer( timeout=1 )
Jon Hall06fd0df2021-01-25 15:50:06 -08001959 ctrl.CLI.logList()
1960
Jon Hall43060f62020-06-23 13:13:33 -07001961 logging = True
1962 try:
1963 logs = main.params.get( 'ONOS_Logging', False )
1964 if logs:
1965 for namespace, level in logs.items():
1966 for ctrl in main.Cluster.active():
1967 ctrl.CLI.logSet( level, namespace )
1968 except AttributeError:
1969 logging = False
1970 utilities.assert_equals( expect=True, actual=logging,
1971 onpass="Set log levels",
1972 onfail="Failed to set log levels" )
Jon Hall06fd0df2021-01-25 15:50:06 -08001973
1974 @staticmethod
1975 def resetOnosLogLevels( main ):
1976 """
1977 Read and reset onos log levels to a previously read set of values
1978 """
1979 main.step( 'Reset logging levels' )
1980 # Get original values incase we want to reset them
1981 ctrl = main.Cluster.active(0)
Jon Halla7b27e62021-06-29 12:13:51 -07001982 ctrl.CLI.clearBuffer( timeout=1 )
Jon Hall06fd0df2021-01-25 15:50:06 -08001983 currentLevels = ctrl.CLI.logList( saveValues=False )
1984 origLevels = ctrl.CLI.logLevels
1985 toBeSet = {}
1986 for logger, level in currentLevels.iteritems():
1987 if logger not in origLevels:
1988 toBeSet[ logger ] = origLevels[ 'ROOT' ]
1989 else:
1990 oldLevel = origLevels[ logger ]
1991 if level != oldLevel:
1992 toBeSet[ logger ] = oldLevel
Jon Hallef1480b2021-03-31 13:37:41 -07001993 # In case a previous test didn't reset
1994 logs = main.params.get( 'ONOS_Logging_Reset', False )
1995 if logs:
1996 for namespace, level in logs.items():
1997 toBeSet[ namespace ] = level
Jon Hall06fd0df2021-01-25 15:50:06 -08001998 logging = True
1999 try:
2000 for logger, level in toBeSet.iteritems():
2001 for ctrl in main.Cluster.active():
2002 ctrl.CLI.logSet( level, logger )
2003 except AttributeError:
2004 logging = False
2005 utilities.assert_equals( expect=True, actual=logging,
2006 onpass="Reset log levels",
2007 onfail="Failed to reset log levels" )