blob: 56389493034ac16cdf55f1593b8b9f5e1c6a87c8 [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 Halldd05bbc2022-01-27 12:14:50 -080027from distutils.util import strtobool
Jon Hall1efcb3f2016-08-23 13:42:15 -070028from core import utilities
29
30
31class Testcaselib:
Pierfb719b12016-09-19 14:51:44 -070032
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070033 useSSH = True
Pierfb719b12016-09-19 14:51:44 -070034
Jon Hall1efcb3f2016-08-23 13:42:15 -070035 @staticmethod
36 def initTest( main ):
37 """
38 - Construct tests variables
39 - GIT ( optional )
40 - Checkout ONOS master branch
41 - Pull latest ONOS code
42 - Building ONOS ( optional )
43 - Install ONOS package
44 - Build ONOS package
45 """
Devin Lim58046fa2017-07-05 16:55:00 -070046 try:
47 from tests.dependencies.ONOSSetup import ONOSSetup
48 main.testSetUp = ONOSSetup()
49 except ImportError:
50 main.log.error( "ONOSSetup not found. exiting the test" )
Devin Lim44075962017-08-11 10:56:37 -070051 main.cleanAndExit()
You Wangd5873482018-01-24 12:30:00 -080052 from tests.dependencies.Network import Network
Jon Hall627b1572020-12-01 12:01:15 -080053 main.persistentSetup = main.params.get( "persistent_setup" )
You Wangd5873482018-01-24 12:30:00 -080054 main.Network = Network()
Jon Hall43060f62020-06-23 13:13:33 -070055 main.physicalNet = False
Devin Lim0c972b72018-02-08 14:53:59 -080056 main.testSetUp.envSetupDescription( False )
Jon Hall39570262020-11-17 12:18:19 -080057 main.logdirBase = main.logdir
Devin Lim58046fa2017-07-05 16:55:00 -070058 stepResult = main.FALSE
59 try:
Devin Lim58046fa2017-07-05 16:55:00 -070060 # Test variables
61 main.cellName = main.params[ 'ENV' ][ 'cellName' ]
62 main.apps = main.params[ 'ENV' ][ 'cellApps' ]
Devin Lim58046fa2017-07-05 16:55:00 -070063 main.path = os.path.dirname( main.testFile )
Devin Lim57221b02018-02-14 15:45:36 -080064 main.useCommonTopo = main.params[ 'DEPENDENCY' ][ 'useCommonTopo' ] == 'True'
65 main.topoPath = main.path + ( "/.." if main.useCommonTopo else "" ) + "/dependencies/"
66 main.useCommonConf = main.params[ 'DEPENDENCY' ][ 'useCommonConf' ] == 'True'
You Wang68568b12019-03-04 11:49:57 -080067 if main.params[ 'DEPENDENCY' ].get( 'useBmv2' ):
68 main.useBmv2 = main.params[ 'DEPENDENCY' ][ 'useBmv2' ] == 'True'
69 else:
70 main.useBmv2 = False
Jon Hall43060f62020-06-23 13:13:33 -070071 if main.useBmv2:
72 main.switchType = main.params[ 'DEPENDENCY' ].get( 'bmv2SwitchType', 'stratum' )
73 else:
74 main.switchType = "ovs"
75
Devin Lim57221b02018-02-14 15:45:36 -080076 main.configPath = main.path + ( "/.." if main.useCommonConf else "" ) + "/dependencies/"
Jon Hallbc1c1c92020-05-27 09:29:30 -070077 main.bmv2Path = "/tools/dev/mininet/"
Devin Lim57221b02018-02-14 15:45:36 -080078 main.forJson = "json/"
Siddeshde1d1692021-09-15 18:12:57 +000079 # main.forcfg = "netcfg/"
Devin Lim57221b02018-02-14 15:45:36 -080080 main.forChart = "chart/"
81 main.forConfig = "conf/"
82 main.forHost = "host/"
You Wang27317572018-03-06 12:13:11 -080083 main.forSwitchFailure = "switchFailure/"
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -080084 main.forLinkFailure = "linkFailure/"
You Wange24d6272018-03-27 21:18:50 -070085 main.forMulticast = "multicast/"
Devin Lim58046fa2017-07-05 16:55:00 -070086 main.topology = main.params[ 'DEPENDENCY' ][ 'topology' ]
You Wangd87b2312018-01-30 12:47:17 -080087 main.topologyLib = main.params[ 'DEPENDENCY' ][ 'lib' ] if 'lib' in main.params[ 'DEPENDENCY' ] else None
88 main.topologyConf = main.params[ 'DEPENDENCY' ][ 'conf' ] if 'conf' in main.params[ 'DEPENDENCY' ] else None
You Wang68568b12019-03-04 11:49:57 -080089 main.bmv2 = "bmv2.py"
Jon Halldac3eae2020-06-05 12:04:06 -070090 main.stratumRoot = main.params[ 'DEPENDENCY'][ 'stratumRoot'] if 'stratumRoot' in main.params[ 'DEPENDENCY' ] else None
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070091 main.scale = ( main.params[ 'SCALE' ][ 'size' ] ).split( "," )
Devin Lim58046fa2017-07-05 16:55:00 -070092 main.maxNodes = int( main.params[ 'SCALE' ][ 'max' ] )
Jon Hall3c0114c2020-08-11 15:07:42 -070093 main.trellisOar = main.params[ 'DEPENDENCY' ][ 'trellisOar' ] if 'trellisOar' in main.params[ 'DEPENDENCY' ] else None
You Wang5bf49592020-07-08 18:47:46 -070094 main.t3Oar = main.params[ 'DEPENDENCY' ][ 't3Oar' ] if 't3Oar' in main.params[ 'DEPENDENCY' ] else None
Jon Hall1efcb3f2016-08-23 13:42:15 -070095
Devin Lim0c972b72018-02-08 14:53:59 -080096 stepResult = main.testSetUp.envSetup( False )
Devin Lim58046fa2017-07-05 16:55:00 -070097 except Exception as e:
98 main.testSetUp.envSetupException( e )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -070099
Jon Hallaa1d9b82020-07-30 13:49:42 -0700100 main.testSetUp.envSetupConclusion( stepResult )
Jon Hall32c90f32021-06-24 16:32:44 -0700101
Siddesh167bc882021-03-23 21:03:43 +0000102 @staticmethod
103 def getTopo():
104 topo = dict()
105 # TODO: Check minFlowCount of leaf for BMv2 switch
106 # (number of spine switch, number of leaf switch, dual-homed, description, minFlowCount - leaf (OvS), minFlowCount - leaf (BMv2))
107 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 }
108 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 }
109 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 }
110 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 }
111 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 }
112 topo[ '4x4' ] = {'spines': 4,'leaves': 4, 'dual-homed': True, 'description': '4x4 dual-homed leaf-spine topology','dual-linked': True }
113 topo[ '2x2staging' ] = { 'spines': 2, 'leaves': 2,'dual-homed': True, 'description': '2x2 leaf-spine topology', 'minFlowOvS': 37, 'minFlow-Stratum': 32 }
114 return topo
Jon Hall1efcb3f2016-08-23 13:42:15 -0700115 @staticmethod
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800116 def installOnos( main, vlanCfg=True, skipPackage=False, cliSleep=10,
117 parallel=True ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700118 """
119 - Set up cell
120 - Create cell file
121 - Set cell file
122 - Verify cell file
123 - Kill ONOS process
124 - Uninstall ONOS cluster
125 - Verify ONOS start up
126 - Install ONOS cluster
127 - Connect to cli
128 """
Siddesh13492972021-03-12 21:09:32 +0000129 # 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
130
Jon Hall1efcb3f2016-08-23 13:42:15 -0700131 # main.scale[ 0 ] determines the current number of ONOS controller
Jon Hall43060f62020-06-23 13:13:33 -0700132 try:
Jon Hall627b1572020-12-01 12:01:15 -0800133 if not main.persistentSetup and main.params.get( 'EXTERNAL_APPS' ):
Jon Hall43060f62020-06-23 13:13:33 -0700134 for app, url in main.params[ 'EXTERNAL_APPS' ].iteritems():
Jon Hall39570262020-11-17 12:18:19 -0800135 main.log.info( "Downloading %s app from %s" % ( app, url ) )
Jon Hall43060f62020-06-23 13:13:33 -0700136 main.ONOSbench.onosFetchApp( url )
137 if not main.apps:
138 main.log.error( "App list is empty" )
139 except Exception as e:
140 main.log.debug( e )
141 main.cleanAndExit()
Jon Hall3c910162018-03-07 14:42:16 -0800142 main.log.info( "Cluster size: " + str( main.Cluster.numCtrls ) )
143 main.log.info( "Cluster ips: " + ', '.join( main.Cluster.getIps() ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700144 main.dynamicHosts = [ 'in1', 'out1' ]
You Wanga0f6ff62018-01-11 15:46:30 -0800145 main.testSetUp.ONOSSetUp( main.Cluster, newCell=True, cellName=main.cellName,
Andreas Pantelopoulos90f0b102018-02-01 13:21:45 -0800146 skipPack=skipPackage,
147 useSSH=Testcaselib.useSSH,
Devin Lim0c972b72018-02-08 14:53:59 -0800148 installParallel=parallel, includeCaseDesc=False )
Devin Lim142b5342017-07-20 15:22:39 -0700149 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -0700150 [ None, main.FALSE ],
You Wang1cdc5f52017-12-19 16:47:51 -0800151 sleep=cliSleep,
Devin Lim142b5342017-07-20 15:22:39 -0700152 attempts=10 )
153 if ready:
154 ready = main.TRUE
155 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700156 onpass="ONOS summary command succeded",
157 onfail="ONOS summary command failed" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700158 if not ready:
159 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700160 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700161
You Wang5bf49592020-07-08 18:47:46 -0700162 # Install segmentrouting and t3 app
Jon Hall3c0114c2020-08-11 15:07:42 -0700163 appInstallResult = main.TRUE
164 if main.trellisOar:
165 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.trellisOar)
You Wang5bf49592020-07-08 18:47:46 -0700166 if main.t3Oar:
167 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.t3Oar)
168 utilities.assert_equals( expect=main.TRUE, actual=appInstallResult,
169 onpass="SR app installation succeded",
170 onfail="SR app installation failed" )
171 if not appInstallResult:
172 main.cleanAndExit()
173
Jon Hall43060f62020-06-23 13:13:33 -0700174 # FIXME: move to somewhere else?
175 switchPrefix = main.params[ 'DEPENDENCY' ].get( 'switchPrefix' )
176 # TODO: Support other pipeconfs/making this configurable
177 if switchPrefix == "tofino":
178 # It seems to take some time for the pipeconfs to be loaded
179 ctrl = main.Cluster.next()
180 for i in range( 120 ):
181 try:
182 main.log.debug( "Checking to see if pipeconfs are loaded" )
183 output = ctrl.CLI.sendline( "pipeconfs" )
184 if "tofino" in output:
185 main.log.debug( "Took around %s seconds for the pipeconf to be loaded" % i )
186 break
187 time.sleep( 1 )
188 except Exception as e:
189 main.log.error( e )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700190
Jon Hall627b1572020-12-01 12:01:15 -0800191 # Install segmentrouting and t3 app
192 appInstallResult = main.TRUE
193 if not main.persistentSetup:
194 if main.trellisOar:
195 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.trellisOar)
196 if main.t3Oar:
197 appInstallResult = appInstallResult and main.ONOSbench.onosAppInstall( main.Cluster.runningNodes[0].ipAddress, main.t3Oar)
198 utilities.assert_equals( expect=main.TRUE, actual=appInstallResult,
199 onpass="SR app installation succeded",
200 onfail="SR app installation failed" )
201 if not appInstallResult:
202 main.cleanAndExit()
203
Jon Hall43060f62020-06-23 13:13:33 -0700204 Testcaselib.setOnosLogLevels( main )
205 Testcaselib.setOnosConfig( main )
Jon Halldac3eae2020-06-05 12:04:06 -0700206
Jon Hall1efcb3f2016-08-23 13:42:15 -0700207 @staticmethod
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800208 def loadCount( main ):
Jon Hall43060f62020-06-23 13:13:33 -0700209 with open( "%s/count/%s.count" % ( main.configPath, main.cfgName ) ) as count:
210 main.count = json.load( count )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800211
212 @staticmethod
Jon Hall43060f62020-06-23 13:13:33 -0700213 def loadJson( main, suffix='' ):
214 with open( "%s%s.json%s" % ( main.configPath + main.forJson,
215 main.cfgName, suffix ) ) as cfg:
Devin Lim57221b02018-02-14 15:45:36 -0800216 main.Cluster.active( 0 ).REST.setNetCfg( json.load( cfg ) )
217
218 @staticmethod
Siddesh606bd872021-06-29 23:42:36 +0000219 def loadNewJson( main, suffix='' ):
Siddeshde1d1692021-09-15 18:12:57 +0000220 with open( "%s%s.json%s" % ( main.configPath + main.forJson,
Siddesh606bd872021-06-29 23:42:36 +0000221 main.cfgName, suffix ) ) as cfg:
222 desiredJSON = json.load ( cfg )
Siddesh1e30a922021-10-06 19:35:09 +0000223 return Testcaselib.netCfgTransition( main, desiredJSON )
Siddesh606bd872021-06-29 23:42:36 +0000224
Siddesh1e30a922021-10-06 19:35:09 +0000225 @staticmethod
226 def netCfgTransition( main, desiredJSON ):
227 returnValue = main.TRUE
228 for device in desiredJSON ["ports"].keys():
229 deviceCfg = desiredJSON[ "ports" ][ device ]
230 currentJSON = main.Cluster.active( 0 ).REST.getNetCfg( subjectClass = "ports", subjectKey = device )
231
232 currentJSON = json.loads( currentJSON )
233 if currentJSON['interfaces'][0]['ips'] != deviceCfg['interfaces'][0]['ips']:
234 currentJSON['interfaces'][0]['ips'] = deviceCfg['interfaces'][0]['ips']
Siddesh606bd872021-06-29 23:42:36 +0000235 data = { 'interfaces': currentJSON['interfaces'] }
Siddesh1e30a922021-10-06 19:35:09 +0000236 A = main.Cluster.active( 0 ).REST.setNetCfg( data , subjectClass = "ports", subjectKey = device )
237 returnValue = returnValue and A
238 currentJSON['interfaces'] = deviceCfg['interfaces']
239 data = { 'interfaces': currentJSON['interfaces'] }
240 B = main.Cluster.active( 0 ).REST.setNetCfg( data , subjectClass = "ports", subjectKey = device )
241 returnValue = returnValue and B
Siddesh606bd872021-06-29 23:42:36 +0000242 return returnValue
243
244 @staticmethod
Jon Hall10e2ab82020-09-15 17:14:54 -0700245 def loadXconnects( main, suffix='' ):
246 with open( "%s%s-xconnects.json%s" % ( main.configPath + main.forJson,
247 main.cfgName, suffix ) ) as cfg:
248 for xconnect in json.load( cfg ).get('xconnects'):
249 main.Cluster.active( 0 ).REST.setXconnectJson( xconnect )
250
251 @staticmethod
Siddesh559d7412021-10-01 06:01:55 +0000252 def loadChart( main, suffix='' ):
Devin Lim57221b02018-02-14 15:45:36 -0800253 try:
Siddesh559d7412021-10-01 06:01:55 +0000254 filename = "%s%s.chart%s" % ( main.configPath + main.forChart,
255 main.cfgName, suffix )
Jon Hall32c90f32021-06-24 16:32:44 -0700256 with open( filename ) as chart:
Jon Hall43060f62020-06-23 13:13:33 -0700257 main.pingChart = json.load( chart )
Devin Lim57221b02018-02-14 15:45:36 -0800258 except IOError:
Jon Hall32c90f32021-06-24 16:32:44 -0700259 main.log.warn( "No chart file found at %s" % filename )
Devin Lim57221b02018-02-14 15:45:36 -0800260
261 @staticmethod
262 def loadHost( main ):
263 with open( "%s%s.host" % ( main.configPath + main.forHost,
264 main.cfgName ) ) as host:
265 main.expectedHosts = json.load( host )
266
267 @staticmethod
You Wang27317572018-03-06 12:13:11 -0800268 def loadSwitchFailureChart( main ):
269 with open( "%s%s.switchFailureChart" % ( main.configPath + main.forSwitchFailure,
270 main.cfgName ) ) as sfc:
271 main.switchFailureChart = json.load( sfc )
272
273 @staticmethod
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800274 def loadLinkFailureChart( main ):
275 with open( "%s%s.linkFailureChart" % ( main.configPath + main.forLinkFailure,
You Wange24d6272018-03-27 21:18:50 -0700276 main.cfgName ) ) as lfc:
277 main.linkFailureChart = json.load( lfc )
278
279 @staticmethod
280 def loadMulticastConfig( main ):
281 with open( "%s%s.multicastConfig" % ( main.configPath + main.forMulticast,
282 main.cfgName ) ) as cfg:
283 main.multicastConfig = json.load( cfg )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800284
285 @staticmethod
Jon Hall1efcb3f2016-08-23 13:42:15 -0700286 def startMininet( main, topology, args="" ):
Jon Hall43060f62020-06-23 13:13:33 -0700287 main.log.info( "Copying mininet topology file to mininet machine" )
You Wangd87b2312018-01-30 12:47:17 -0800288 copyResult = main.ONOSbench.scp( main.Mininet1,
289 main.topoPath + main.topology,
You Wang5da39c82018-04-26 22:55:08 -0700290 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800291 direction="to" )
292 if main.topologyLib:
293 for lib in main.topologyLib.split(","):
294 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
295 main.topoPath + lib,
You Wang5da39c82018-04-26 22:55:08 -0700296 main.Mininet1.home + "custom",
You Wangd87b2312018-01-30 12:47:17 -0800297 direction="to" )
298 if main.topologyConf:
You Wanga877ea42018-04-05 15:27:40 -0700299 import re
300 controllerIPs = [ ctrl.ipAddress for ctrl in main.Cluster.runningNodes ]
301 index = 0
Jon Hall43060f62020-06-23 13:13:33 -0700302 destDir = "~/"
303 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
304 destDir = "/tmp/mn_conf/"
305 # Try to ensure the destination exists
You Wangd87b2312018-01-30 12:47:17 -0800306 for conf in main.topologyConf.split(","):
You Wanga877ea42018-04-05 15:27:40 -0700307 # Update zebra configurations with correct ONOS instance IP
308 if conf in [ "zebradbgp1.conf", "zebradbgp2.conf" ]:
309 ip = controllerIPs[ index ]
310 index = ( index + 1 ) % len( controllerIPs )
311 with open( main.configPath + main.forConfig + conf ) as f:
312 s = f.read()
313 s = re.sub( r"(fpm connection ip).*(port 2620)", r"\1 " + ip + r" \2", s )
314 with open( main.configPath + main.forConfig + conf, "w" ) as f:
315 f.write( s )
You Wangd87b2312018-01-30 12:47:17 -0800316 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Devin Lim57221b02018-02-14 15:45:36 -0800317 main.configPath + main.forConfig + conf,
Jon Hall43060f62020-06-23 13:13:33 -0700318 destDir,
You Wangd87b2312018-01-30 12:47:17 -0800319 direction="to" )
You Wang68568b12019-03-04 11:49:57 -0800320 copyResult = copyResult and main.ONOSbench.scp( main.Mininet1,
Jon Hallbc1c1c92020-05-27 09:29:30 -0700321 main.ONOSbench.home + main.bmv2Path + main.bmv2,
You Wang68568b12019-03-04 11:49:57 -0800322 main.Mininet1.home + "custom",
323 direction="to" )
Jon Hall9b0de1f2020-08-24 15:38:04 -0700324
325 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
326 # move the config files into home
327 main.Mininet1.handle.sendline( "cp config/* . " )
328 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
329 main.log.debug( main.Mininet1.handle.before + main.Mininet1.handle.after )
330 main.Mininet1.handle.sendline( "ls -al " )
331 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
332 main.log.debug( main.Mininet1.handle.before + main.Mininet1.handle.after )
333
You Wangd87b2312018-01-30 12:47:17 -0800334 stepResult = copyResult
335 utilities.assert_equals( expect=main.TRUE,
336 actual=stepResult,
337 onpass="Successfully copied topo files",
338 onfail="Failed to copy topo files" )
Jon Halldac3eae2020-06-05 12:04:06 -0700339 if main.stratumRoot:
340 main.Mininet1.handle.sendline( "export STRATUM_ROOT=" + str( main.stratumRoot ) )
Jon Hall3c0114c2020-08-11 15:07:42 -0700341 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700342 main.step( "Starting Mininet Topology" )
Jonghwan Hyun3731d6a2017-10-19 11:59:31 -0700343 arg = "--onos-ip=%s %s" % (",".join([ctrl.ipAddress for ctrl in main.Cluster.runningNodes]), args)
Jon Hall1efcb3f2016-08-23 13:42:15 -0700344 main.topology = topology
345 topoResult = main.Mininet1.startNet(
You Wang5da39c82018-04-26 22:55:08 -0700346 topoFile=main.Mininet1.home + "custom/" + main.topology, args=arg )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700347 stepResult = topoResult
348 utilities.assert_equals( expect=main.TRUE,
349 actual=stepResult,
350 onpass="Successfully loaded topology",
351 onfail="Failed to load topology" )
352 # Exit if topology did not load properly
353 if not topoResult:
Devin Lim44075962017-08-11 10:56:37 -0700354 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700355 if main.useBmv2:
Jon Hall3c0114c2020-08-11 15:07:42 -0700356 main.step( "Configure switches in ONOS" )
Jon Hall43060f62020-06-23 13:13:33 -0700357 # Upload the net-cfg file created for each switch
358 filename = "onos-netcfg.json"
359 switchPrefix = main.params[ 'DEPENDENCY' ].get( 'switchPrefix', "bmv2" )
Jon Hall3c0114c2020-08-11 15:07:42 -0700360 switchNetCfg = main.TRUE
Jon Hall43060f62020-06-23 13:13:33 -0700361 for switch in main.Mininet1.getSwitches( switchRegex=r"(StratumBmv2Switch)|(Bmv2Switch)" ).keys():
362 path = "/tmp/mn-stratum/%s/" % switch
363 dstPath = "/tmp/"
364 dstFileName = "%s-onos-netcfg.json" % switch
365 main.ONOSbench1.scp( main.Mininet1,
366 "%s%s" % ( path, filename ),
367 "%s%s" % ( dstPath, dstFileName ),
368 "from" )
369 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 -0700370 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
Jon Hall43060f62020-06-23 13:13:33 -0700371 # Configure managementAddress
372 main.ONOSbench1.handle.sendline( "sudo sed -i 's/localhost/%s/g' %s%s" % ( main.Mininet1.ip_address, dstPath, dstFileName ) )
373 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
374 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
375 # Configure device id
376 main.ONOSbench1.handle.sendline( "sudo sed -i 's/device:%s/device:%s:%s/g' %s%s" % ( switch, switchPrefix, switch, dstPath, dstFileName ) )
377 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
378 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
379 # Configure device name
Jon Hall39570262020-11-17 12:18:19 -0800380 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 -0700381 main.ONOSbench1.handle.expect( main.ONOSbench1.prompt )
382 main.log.debug( main.ONOSbench1.handle.before + main.ONOSbench1.handle.after )
Jon Hall3c0114c2020-08-11 15:07:42 -0700383 node = main.Cluster.active(0)
384 switchNetCfg = switchNetCfg and node.onosNetCfg( node.server.ip_address,
385 dstPath,
386 dstFileName,
387 user=node.REST.user_name,
388 password=node.REST.pwd )
389 # Stop test if we fail to push switch netcfg
390 utilities.assert_equals( expect=main.TRUE,
391 actual=switchNetCfg,
392 onpass="Successfully pushed switch netcfg",
393 onfail="Failed to configure switches in onos" )
394 if not switchNetCfg:
395 main.cleanAndExit()
Jon Hall43060f62020-06-23 13:13:33 -0700396 # Make sure hosts make some noise
397 Testcaselib.discoverHosts( main )
398
399 @staticmethod
400 def discoverHosts( main ):
401 # TODO add option to only select specific hosts
402 if hasattr( main, "Mininet1" ):
403 network = main.Mininet1
404 elif hasattr( main, "NetworkBench" ):
405 network = main.NetworkBench
406 else:
407 main.log.warn( "Could not find component for test network, skipping host discovery" )
408 return
409 network.discoverHosts()
Jon Hall1efcb3f2016-08-23 13:42:15 -0700410
411 @staticmethod
Jon Hall06fd0df2021-01-25 15:50:06 -0800412 def connectToPhysicalNetwork( main, hostDiscovery=True ):
You Wang84f981d2018-01-12 16:11:50 -0800413 main.step( "Connecting to physical netowrk" )
Jon Hall43060f62020-06-23 13:13:33 -0700414 main.physicalNet = True
You Wang84f981d2018-01-12 16:11:50 -0800415 topoResult = main.NetworkBench.connectToNet()
416 stepResult = topoResult
417 utilities.assert_equals( expect=main.TRUE,
418 actual=stepResult,
Jon Hall43060f62020-06-23 13:13:33 -0700419 onpass="Successfully connected to topology",
420 onfail="Failed to connect to topology" )
You Wang84f981d2018-01-12 16:11:50 -0800421 # Exit if topology did not load properly
422 if not topoResult:
423 main.cleanAndExit()
424
Jon Hall627b1572020-12-01 12:01:15 -0800425 if not main.persistentSetup:
426 # Perform any optional setup
427 for switch in main.NetworkBench.switches:
428 if hasattr( switch, "setup" ):
429 switch.setup() # We might not need this
Jon Hall43060f62020-06-23 13:13:33 -0700430
Jon Hall627b1572020-12-01 12:01:15 -0800431 main.step( "Assign switches to controllers." )
432 stepResult = main.TRUE
433 switches = main.NetworkBench.getSwitches()
434 pool = []
435 for name in switches.keys():
436 # NOTE: although this terminology is ovsdb centric, we can use this function for other switches too
437 # e.g. push onos net-cfg for stratum switches
438 thread = main.Thread( target=main.NetworkBench.assignSwController,
439 name="assignSwitchToController",
440 args=[ name, main.Cluster.getIps(), '6653' ] )
441 pool.append( thread )
442 thread.start()
443 for thread in pool:
444 thread.join( 300 )
445 if not thread.result:
446 stepResult = main.FALSE
447 utilities.assert_equals( expect=main.TRUE,
448 actual=stepResult,
449 onpass="Successfully assign switches to controllers",
450 onfail="Failed to assign switches to controllers" )
You Wang84f981d2018-01-12 16:11:50 -0800451
You Wang4cc61912018-08-28 10:10:58 -0700452 # Check devices
453 Testcaselib.checkDevices( main, switches=int( main.params[ 'TOPO' ][ 'switchNum' ] ) )
You Wang4cc61912018-08-28 10:10:58 -0700454 # Connecting to hosts that only have data plane connectivity
455 main.step( "Connecting inband hosts" )
456 stepResult = main.Network.connectInbandHosts()
457 utilities.assert_equals( expect=main.TRUE,
458 actual=stepResult,
459 onpass="Successfully connected inband hosts",
460 onfail="Failed to connect inband hosts" )
Jon Hall06fd0df2021-01-25 15:50:06 -0800461 if hostDiscovery:
462 Testcaselib.discoverHosts( main )
You Wang4cc61912018-08-28 10:10:58 -0700463
You Wang84f981d2018-01-12 16:11:50 -0800464 @staticmethod
You Wang5df1c6d2018-04-06 18:02:02 -0700465 def saveOnosDiagnostics( main ):
466 """
467 Get onos-diags.tar.gz and save it to the log directory.
468 suffix: suffix string of the file name. E.g. onos-diags-case1.tar.gz
469 """
470 main.log.info( "Collecting onos-diags..." )
Jon Halla8cf76a2021-10-05 14:31:47 -0700471 podNames = []
Siddesha2938fe2021-04-06 02:46:06 +0000472 for ctrl in main.Cluster.runningNodes:
Jon Halla8cf76a2021-10-05 14:31:47 -0700473 if ctrl.k8s:
474 podNames.append( ctrl.k8s.podName )
475 else:
476 main.ONOSbench.onosDiagnostics( [ctrl.ipAddress], main.logdir, "-CASE%d" % main.CurrentTestCaseNumber, onosPortnumber=ctrl.REST.port )
477 if podNames:
478 main.ONOSbench.onosDiagnosticsK8s( podNames, main.logdir, "-CASE%d" % main.CurrentTestCaseNumber )
You Wang5df1c6d2018-04-06 18:02:02 -0700479
480 @staticmethod
Devin Lim142b5342017-07-20 15:22:39 -0700481 def config( main, cfgName ):
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700482 main.spines = []
Piera2a7e1b2016-10-04 11:51:43 -0700483
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700484 main.failures = int( main.params[ 'failures' ] )
485 main.cfgName = cfgName
Piera2a7e1b2016-10-04 11:51:43 -0700486
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700487 if main.cfgName == '2x2':
488 spine = {}
489 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
490 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
491 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700492
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700493 spine = {}
494 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
495 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
496 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700497
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700498 elif main.cfgName == '4x4':
499 spine = {}
500 spine[ 'name' ] = main.params[ 'switches' ][ 'spine1' ]
501 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid1' ]
502 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700503
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700504 spine = {}
505 spine[ 'name' ] = main.params[ 'switches' ][ 'spine2' ]
506 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid2' ]
507 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700508
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700509 spine = {}
510 spine[ 'name' ] = main.params[ 'switches' ][ 'spine3' ]
511 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid3' ]
512 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700513
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700514 spine = {}
515 spine[ 'name' ] = main.params[ 'switches' ][ 'spine4' ]
516 spine[ 'dpid' ] = main.params[ 'switches' ][ 'spinedpid4' ]
517 main.spines.append( spine )
Piera2a7e1b2016-10-04 11:51:43 -0700518
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700519 else:
Piera2a7e1b2016-10-04 11:51:43 -0700520 main.log.error( "Configuration failed!" )
Devin Lim44075962017-08-11 10:56:37 -0700521 main.cleanAndExit()
You Wang27317572018-03-06 12:13:11 -0800522
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800523 @staticmethod
524 def addStaticOnosRoute( main, subnet, intf):
525 """
526 Adds an ONOS static route with the use route-add command.
527 """
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -0800528 routeResult = main.Cluster.active( 0 ).addStaticRoute(subnet, intf)
529
Piera2a7e1b2016-10-04 11:51:43 -0700530 @staticmethod
You Wangc02f3be2018-05-18 12:14:23 -0700531 def checkGroupsForBuckets( main, deviceId, subnetDict, routingTable=30 ):
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700532 """
533 Check number of groups for each subnet on device deviceId and matches
534 it with an expected value. subnetDict is a dictionarty containing values
535 of the type "10.0.1.0/24" : 5.
536 """
You Wangc02f3be2018-05-18 12:14:23 -0700537 main.step( "Checking if number of groups for subnets in device {0} is as expected.".format( deviceId ) )
538 groups = main.Cluster.active( 0 ).CLI.getGroups( deviceId, groupType="select" )
539 flows = main.Cluster.active( 0 ).CLI.flows( jsonFormat=False, device=deviceId )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700540
You Wangc02f3be2018-05-18 12:14:23 -0700541 result = main.TRUE
542 for subnet, numberInSelect in subnetDict.iteritems():
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700543 for flow in flows.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700544 if "tableId={0}".format( routingTable ) in flow and subnet in flow:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700545 # this will match the group id that this flow entry points to, for example :
546 # 0x70000041 in flow entry which contains "deferred=[GROUP:0x70000041], transition=TABLE:60,"
You Wangc02f3be2018-05-18 12:14:23 -0700547 groupId = re.search( r".*GROUP:(0x.*)], transition.*", flow ).groups()[0]
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700548 count = 0
549 for group in groups.splitlines():
You Wangc02f3be2018-05-18 12:14:23 -0700550 if 'id={0}'.format( groupId ) in group:
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700551 count += 1
You Wangc02f3be2018-05-18 12:14:23 -0700552 if count - 1 != numberInSelect:
553 result = main.FALSE
554 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 ) )
555 utilities.assert_equals( expect=main.TRUE, actual=result,
556 onpass="All bucket numbers are as expected",
557 onfail="Some bucket numbers are not as expected" )
Andreas Pantelopoulosdf5061f2018-05-15 11:46:59 -0700558
559 @staticmethod
Jon Hall32c90f32021-06-24 16:32:44 -0700560 def checkFlows( main, minFlowCount, tag="", dumpFlows=True, sleep=10 ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700561 main.step(
Jon Hall39570262020-11-17 12:18:19 -0800562 "Check whether the flow count is >= %s" % minFlowCount )
Jonghwan Hyun76a02b72018-01-30 16:40:48 +0900563 if tag == "":
564 tag = 'CASE%d' % main.CurrentTestCaseNumber
Devin Lim142b5342017-07-20 15:22:39 -0700565 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowCount,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700566 main.FALSE,
567 kwargs={ 'min': minFlowCount },
568 attempts=10,
You Wang1cdc5f52017-12-19 16:47:51 -0800569 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800570 if count == main.FALSE:
571 count = main.Cluster.active( 0 ).CLI.checkFlowCount()
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700572 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700573 expect=True,
Jon Hall39570262020-11-17 12:18:19 -0800574 actual=( count >= minFlowCount ),
Jon Hall43060f62020-06-23 13:13:33 -0700575 onpass="Flow count looks correct; found %s, expecting at least %s" % ( count, minFlowCount ),
576 onfail="Flow count looks wrong; found %s, expecting at least %s" % ( count, minFlowCount ) )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700577
578 main.step( "Check whether all flow status are ADDED" )
Devin Lim142b5342017-07-20 15:22:39 -0700579 flowCheck = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowsState,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700580 main.FALSE,
581 kwargs={ 'isPENDING': False },
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800582 attempts=5,
You Wang1cdc5f52017-12-19 16:47:51 -0800583 sleep=sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700584 utilities.assertEquals(
Jon Hall1efcb3f2016-08-23 13:42:15 -0700585 expect=main.TRUE,
586 actual=flowCheck,
587 onpass="Flow status is correct!",
588 onfail="Flow status is wrong!" )
Jon Hall32c90f32021-06-24 16:32:44 -0700589 if dumpFlows:
Devin Lim142b5342017-07-20 15:22:39 -0700590 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700591 "flows",
592 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800593 tag + "_FlowsBefore",
594 cliPort=main.Cluster.active(0).CLI.karafPort )
Devin Lim142b5342017-07-20 15:22:39 -0700595 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
Pier50f0bc62016-09-07 17:53:40 -0700596 "groups",
597 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800598 tag + "_GroupsBefore",
599 cliPort=main.Cluster.active(0).CLI.karafPort )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700600
601 @staticmethod
Pier6a0c4de2018-03-18 16:01:30 -0700602 def checkDevices( main, switches, tag="", sleep=10 ):
603 main.step(
604 "Check whether the switches count is equal to %s" % switches )
605 if tag == "":
606 tag = 'CASE%d' % main.CurrentTestCaseNumber
607 result = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
608 main.FALSE,
609 kwargs={ 'numoswitch': switches},
610 attempts=10,
611 sleep=sleep )
612 utilities.assert_equals( expect=main.TRUE, actual=result,
613 onpass="Device up successful",
614 onfail="Failed to boot up devices?" )
615
616 @staticmethod
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800617 def checkFlowsByDpid( main, dpid, minFlowCount, sleep=10 ):
618 main.step(
Jon Hall39570262020-11-17 12:18:19 -0800619 "Check whether the flow count of device %s >= than %s" % ( dpid, minFlowCount ) )
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800620 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
621 main.FALSE,
622 args=( dpid, minFlowCount ),
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800623 attempts=5,
624 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800625 if count == main.FALSE:
626 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800627 utilities.assertEquals(
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800628 expect=True,
Jon Hall39570262020-11-17 12:18:19 -0800629 actual=( count >= minFlowCount ),
Jonghwan Hyuncf2345c2018-02-26 11:07:54 -0800630 onpass="Flow count looks correct: " + str( count ),
steven30801eccfe212019-01-24 13:00:42 +0800631 onfail="Flow count looks wrong: " + str( count ) )
Jonghwan Hyun98fb40a2018-01-04 16:16:28 -0800632
633 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700634 def checkFlowEqualityByDpid( main, dpid, flowCount, sleep=10 ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800635 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700636 "Check whether the flow count of device %s is equal to %s" % ( dpid, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800637 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkFlowAddedCount,
638 main.FALSE,
Jon Hall9677ed32018-04-24 11:16:23 -0700639 args=( dpid, flowCount, False, 1 ),
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800640 attempts=5,
641 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800642 if count == main.FALSE:
643 count = main.Cluster.active( 0 ).CLI.checkFlowAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800644 utilities.assertEquals(
645 expect=True,
steven30801eccfe212019-01-24 13:00:42 +0800646 actual=( count == flowCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700647 onpass="Flow count looks correct: " + str( count ) ,
648 onfail="Flow count looks wrong. found {}, should be {}.".format( count, flowCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800649
650 @staticmethod
651 def checkGroupEqualityByDpid( main, dpid, groupCount, sleep=10):
652 main.step(
Jon Hall43060f62020-06-23 13:13:33 -0700653 "Check whether the group count of device %s is equal to %s" % ( dpid, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800654 count = utilities.retry( main.Cluster.active( 0 ).CLI.checkGroupAddedCount,
655 main.FALSE,
656 args=( dpid, groupCount, False, 1),
657 attempts=5,
658 sleep=sleep )
steven30801eccfe212019-01-24 13:00:42 +0800659 if count == main.FALSE:
steven3080123997972019-01-29 17:01:40 +0800660 count = main.Cluster.active( 0 ).CLI.checkGroupAddedCount( dpid )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800661 utilities.assertEquals(
662 expect=True,
663 actual=( count == groupCount ),
Jon Hall9677ed32018-04-24 11:16:23 -0700664 onpass="Group count looks correct: " + str( count ) ,
665 onfail="Group count looks wrong. found {}, should be {}.".format( count, groupCount ) )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800666
667 @staticmethod
Jon Hall9677ed32018-04-24 11:16:23 -0700668 def checkFlowsGroupsFromFile( main ):
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800669
670 for dpid, values in main.count.items():
671 flowCount = values["flows"]
672 groupCount = values["groups"]
Jon Hall9677ed32018-04-24 11:16:23 -0700673 main.log.report( "Check flow count for dpid " + str( dpid ) +
674 ", should be " + str( flowCount ) )
675 Testcaselib.checkFlowEqualityByDpid( main, dpid, flowCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800676
Jon Hall9677ed32018-04-24 11:16:23 -0700677 main.log.report( "Check group count for dpid " + str( dpid ) +
678 ", should be " + str( groupCount ) )
679 Testcaselib.checkGroupEqualityByDpid( main, dpid, groupCount )
Andreas Pantelopoulos9173d442018-03-01 17:07:37 -0800680
681 return
682
683 @staticmethod
Jon Hall32c90f32021-06-24 16:32:44 -0700684 def pingAll( main, tag="", dumpFlows=True, acceptableFailed=0, basedOnIp=False,
Jon Hall06fd0df2021-01-25 15:50:06 -0800685 sleep=10, retryAttempts=1, skipOnFail=False, useScapy=True ):
You Wangf19d9f42018-02-23 16:34:19 -0800686 '''
You Wangba231e72018-03-01 13:18:21 -0800687 Verify connectivity between hosts according to the ping chart
688 acceptableFailed: max number of acceptable failed pings.
You Wangf19d9f42018-02-23 16:34:19 -0800689 basedOnIp: if True, run ping or ping6 based on suffix of host names
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800690 retryAttempts: the number of retry ping. Only works for IPv4 hosts.
You Wangf19d9f42018-02-23 16:34:19 -0800691 '''
You Wangba231e72018-03-01 13:18:21 -0800692 main.log.report( "Check host connectivity" )
693 main.log.debug( "Ping chart: %s" % main.pingChart )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800694 if tag == "":
695 tag = 'CASE%d' % main.CurrentTestCaseNumber
696 for entry in main.pingChart.itervalues():
You Wangba231e72018-03-01 13:18:21 -0800697 main.log.debug( "Entry in ping chart: %s" % entry )
698 expect = entry[ 'expect' ]
699 if expect == "Unidirectional":
700 # Verify ping from each src host to each dst host
701 src = entry[ 'src' ]
702 dst = entry[ 'dst' ]
703 expect = main.TRUE
704 main.step( "Verify unidirectional connectivity from %s to %s with tag %s" % ( str( src ), str( dst ), tag ) )
705 if basedOnIp:
706 if ("v4" in src[0]):
707 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
708 utilities.assert_equals( expect=expect, actual=pa,
709 onpass="IPv4 connectivity successfully tested",
710 onfail="IPv4 connectivity failed" )
711 if ("v6" in src[0]):
712 pa = main.Network.pingallHostsUnidirectional( src, dst, ipv6=True, acceptableFailed=acceptableFailed )
713 utilities.assert_equals( expect=expect, actual=pa,
714 onpass="IPv6 connectivity successfully tested",
715 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700716 elif main.physicalNet:
717 pa = main.NetworkBench.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed, useScapy=True )
718 utilities.assert_equals( expect=expect, actual=pa,
719 onpass="IP connectivity successfully tested",
720 onfail="IP connectivity failed" )
721
You Wangba231e72018-03-01 13:18:21 -0800722 else:
723 pa = main.Network.pingallHostsUnidirectional( src, dst, acceptableFailed=acceptableFailed )
724 utilities.assert_equals( expect=expect, actual=pa,
725 onpass="IP connectivity successfully tested",
726 onfail="IP connectivity failed" )
727 else:
728 # Verify ping between each host pair
729 hosts = entry[ 'hosts' ]
730 try:
731 expect = main.TRUE if str(expect).lower() == 'true' else main.FALSE
732 except:
733 expect = main.FALSE
734 main.step( "Verify full connectivity for %s with tag %s" % ( str( hosts ), tag ) )
735 if basedOnIp:
736 if ("v4" in hosts[0]):
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800737 pa = utilities.retry( main.Network.pingallHosts,
738 main.FALSE if expect else main.TRUE,
Jon Hall43060f62020-06-23 13:13:33 -0700739 args=(hosts, ),
740 kwargs={ 'ipv6': False },
Jonghwan Hyun812c70f2018-02-16 16:33:16 -0800741 attempts=retryAttempts,
742 sleep=sleep )
You Wangba231e72018-03-01 13:18:21 -0800743 utilities.assert_equals( expect=expect, actual=pa,
744 onpass="IPv4 connectivity successfully tested",
745 onfail="IPv4 connectivity failed" )
746 if ("v6" in hosts[0]):
747 pa = main.Network.pingIpv6Hosts( hosts, acceptableFailed=acceptableFailed )
748 utilities.assert_equals( expect=expect, actual=pa,
749 onpass="IPv6 connectivity successfully tested",
750 onfail="IPv6 connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700751 elif main.physicalNet:
Siddesh559d7412021-10-01 06:01:55 +0000752 pa = main.Network.pingallHosts( hosts, ipv6=True, useScapy=useScapy, returnResult=True )
753 combinedResult = True
754 for result in pa:
755 expectedResult = None
756 for ping in main.pingChart.values():
757 if result["src"] in ping["hosts"] and result["dst"] in ping["hosts"]:
758 # Check if the vlan in ping is the same as in the result. If true, set the expected result to result at expect
759 # If expected result is not the same as the actual result, then the combined result is false
760 # if we cannot find the expected result, then expect should be the default between the hosts
761 if str(result["vlan"]) in ping.get("vlans", [] ):
762 expectedResult = ping["vlans"].get(str(result["vlan"]))
763 if expectedResult is None:
764 expectedRresult = expect
Siddeshb86c0e92021-10-05 22:14:45 +0000765 if expectedResult.lower() == "true":
766 expectedResult = main.TRUE
767 else:
768 expectedResult = main.FALSE
Siddesh559d7412021-10-01 06:01:55 +0000769 if expectedResult != result["result"]:
770 combinedResult = False
771 utilities.assert_equals( expect=True, actual=combinedResult,
Jon Hall43060f62020-06-23 13:13:33 -0700772 onpass="IP connectivity successfully tested",
773 onfail="IP connectivity failed" )
You Wangba231e72018-03-01 13:18:21 -0800774 else:
You Wangf19d9f42018-02-23 16:34:19 -0800775 pa = main.Network.pingallHosts( hosts )
776 utilities.assert_equals( expect=expect, actual=pa,
You Wangba231e72018-03-01 13:18:21 -0800777 onpass="IP connectivity successfully tested",
778 onfail="IP connectivity failed" )
Jon Hall43060f62020-06-23 13:13:33 -0700779 if skipOnFail and pa != expect:
You Wang24ad2f52018-04-10 10:47:12 -0700780 Testcaselib.cleanup( main, copyKarafLog=False )
You Wang5df1c6d2018-04-06 18:02:02 -0700781 main.skipCase()
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800782
Jon Hall32c90f32021-06-24 16:32:44 -0700783 if dumpFlows:
784 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
785 "flows",
786 main.logdir,
787 tag + "_FlowsOn",
788 cliPort=main.Cluster.active(0).CLI.karafPort )
789 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
790 "groups",
791 main.logdir,
792 tag + "_GroupsOn",
793 cliPort=main.Cluster.active(0).CLI.karafPort )
794
795 @staticmethod
Jon Hall66acd622022-02-02 15:20:13 -0800796 def getFabricIntfIp( main, hostIp, hostsJson=None, netcfgJson=None ):
797 '''
798 Get the fabric interface IP of a given host
799 '''
800 # NOTE: We pass in json instead of loading them here since finding all host's gateway ips
801 # would require 2 rest calls per host
802 if not hostsJson:
803 hostsJson = json.loads( main.Cluster.active( 0 ).hosts() )
804 if not netcfgJson:
805 netcfgJson = json.loads( main.Cluster.active( 0 ).getNetCfg( subjectClass='ports') )
806 ips = []
807 fabricIntfIp = None
808 for obj in hostsJson:
809 if hostIp in obj['ipAddresses']:
810 for location in obj['locations']:
811 main.log.debug( location )
812 did = location['elementId'].encode( 'utf-8' )
813 port = location['port'].encode( 'utf-8' )
814 m = re.search( '\((\d+)\)', port )
815 if m:
816 port = m.group(1)
817 portId = "%s/%s" % ( did, port )
818 # Lookup ip assigned to this network port
819 ips.extend( [ x.encode( 'utf-8' ) for x in netcfgJson[ portId ][ 'interfaces' ][0][ 'ips' ] ] )
820 ips = set( ips )
821 ipRE = r'(\d+\.\d+\.\d+\.\d+)/\d+|([\w,:]*)/\d+'
822 for ip in ips:
823 ipMatch = re.search( ipRE, ip )
824 if ipMatch:
825 fabricIntfIp = ipMatch.group(1)
826 main.log.debug( "Found %s as gateway ip for %s" % ( fabricIntfIp, hostIp ) )
827 # FIXME: How to chose the correct one if there are multiple? look at subnets
828 return fabricIntfIp
829
830 @staticmethod
Jon Hall32c90f32021-06-24 16:32:44 -0700831 def pingAllFabricIntfs( main, srcList, tag="", dumpFlows=True, skipOnFail=False ):
832 '''
833 Verify connectivity between hosts and their fabric interfaces
834 '''
835 main.log.report( "Check host connectivity with fabric" )
836 if tag == "":
837 tag = 'CASE%d' % main.CurrentTestCaseNumber
838 expect = main.TRUE
Jon Hall66acd622022-02-02 15:20:13 -0800839
Jon Hall32c90f32021-06-24 16:32:44 -0700840 hostsJson = json.loads( main.Cluster.active( 0 ).hosts() )
841 netcfgJson = json.loads( main.Cluster.active( 0 ).getNetCfg( subjectClass='ports') )
842 for hostname in srcList:
843 try:
844 hostComponent = main.Network.hosts[ str( hostname ) ]
845 srcIface = hostComponent.interfaces[0].get( 'name' )
846 main.step( "Verify fabric connectivity for %s with tag %s" % ( str( hostname ), tag ) )
847 #Get host location, check netcfg for that port's ip
848 hostIp = hostComponent.getIPAddress( iface=srcIface )
849 main.log.warn( "Looking for %s" % hostIp )
Jon Hall66acd622022-02-02 15:20:13 -0800850 fabricIntfIp = Testcaselib.getFabricIntfIp( main, hostIp, hostsJson, netcfgJson )
851 pa = hostComponent.ping( fabricIntfIp, interface=srcIface )
852 utilities.assert_equals( expect=expect, actual=pa,
853 onpass="IP connectivity successfully tested",
854 onfail="IP connectivity failed" )
855 if pa != expect:
856 if skipOnFail:
857 Testcaselib.cleanup( main, copyKarafLog=False )
858 main.skipCase()
Jon Hall32c90f32021-06-24 16:32:44 -0700859 except ValueError:
860 main.log.exception( "Could not get gateway ip for %s" % hostname )
861
862 if dumpFlows:
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800863 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
864 "flows",
865 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800866 tag + "_FlowsOn",
867 cliPort=main.Cluster.active(0).CLI.karafPort )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800868 main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress,
869 "groups",
870 main.logdir,
Jon Hall06fd0df2021-01-25 15:50:06 -0800871 tag + "_GroupsOn",
872 cliPort=main.Cluster.active(0).CLI.karafPort )
Andreas Pantelopoulosf6ed5012018-02-08 21:26:01 -0800873
874 @staticmethod
Jon Hall326501b2021-08-31 10:14:55 -0700875 def populateHostsVlan( main, hostList ):
876 """
877 Set the vlan for each host.
878 Checks what interface the host is configured on and reads the netcfg for that interface
879 """
880 import json
881 import re
882 hostsJson = json.loads( main.Cluster.active( 0 ).hosts() )
883 netcfgJson = json.loads( main.Cluster.active( 0 ).getNetCfg( subjectClass='ports') )
884 for hostname in hostList:
885 try:
886 hostComponent = main.Network.hosts[ str( hostname ) ]
887 srcIface = hostComponent.interfaces[0].get( 'name' )
888 #Get host location, check netcfg for that port's ip
889 hostIp = hostComponent.getIPAddress( iface=srcIface )
Siddeshde1d1692021-09-15 18:12:57 +0000890 if not hostIp:
891 hostIp=hostComponent.interfaces[0].get( 'ips' )[0]
Jon Hall326501b2021-08-31 10:14:55 -0700892 main.log.warn( "Looking for allowed vlans for %s" % hostIp )
893 vlans = []
894 for obj in hostsJson:
895 if hostIp in obj['ipAddresses']:
896 for location in obj['locations']:
897 did = location['elementId'].encode( 'utf-8' )
898 port = location['port'].encode( 'utf-8' )
899 m = re.search( '\((\d+)\)', port )
900 if m:
901 port = m.group(1)
902 portId = "%s/%s" % ( did, port )
903 # Lookup ip assigned to this network port
904 # Valid host vlans:
905 # None if vlan-untagged
906 # vlanid if vlan-tagged: vlanid
907 # None if vlan-native + any vlan ids from vlan-tagged
908 intf = netcfgJson[ portId ][ 'interfaces' ][0]
Siddeshde1d1692021-09-15 18:12:57 +0000909 main.log.debug( intf )
Jon Hall326501b2021-08-31 10:14:55 -0700910 for field in intf.keys():
911 if "vlan-untagged" in field:
912 vlans.append( None )
913 if "vlan-tagged" in field:
Siddeshde1d1692021-09-15 18:12:57 +0000914 for VLAN in intf[ field ]:
915 vlans.append( VLAN )
Jon Hall326501b2021-08-31 10:14:55 -0700916 if "vlan-native" in field:
917 vlans.append( None )
918 if len( vlans ) == 0:
919 main.log.debug( "Could not find vlan setting for %s" % hostname )
920 vlans = set( vlans )
Siddeshd9840842021-08-06 19:26:05 +0000921 hostComponent.interfaces[0][ 'vlan' ] = list( vlans )
Jon Hall326501b2021-08-31 10:14:55 -0700922 main.log.debug( repr( hostComponent.interfaces[0] ) )
923 main.log.debug( repr( hostComponent.interfaces[0].get( 'vlan' ) ) )
924 except ValueError:
925 main.log.exception( "Error getting vlans for %s" % hostname )
926
927
928 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700929 def killLink( main, end1, end2, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -0700930 """
931 end1,end2: identify the switches, ex.: 'leaf1', 'spine1'
932 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
933 Kill a link and verify ONOS can see the proper link change
934 """
Jon Halla604fd42018-05-04 14:27:27 -0700935 if sleep is None:
936 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
937 else:
938 sleep = float( sleep )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -0700939 main.step( "Kill link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -0700940 linkDown = main.Network.link( END1=end1, END2=end2, OPTION="down" )
941 linkDown = linkDown and main.Network.link( END2=end1, END1=end2, OPTION="down" )
Jon Hall214f88b2020-09-21 10:21:42 -0700942 utilities.assert_equals( expect=main.TRUE, actual=linkDown,
943 onpass="Link down successful",
944 onfail="Failed to turn off link?" )
Jon Halla604fd42018-05-04 14:27:27 -0700945 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -0700946 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700947 "Waiting %s seconds for link down to be discovered" % sleep )
948 time.sleep( sleep )
Jon Hall214f88b2020-09-21 10:21:42 -0700949 main.step( "Checking topology after link down" )
Devin Lim142b5342017-07-20 15:22:39 -0700950 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -0700951 main.FALSE,
952 kwargs={ 'numoswitch': switches,
953 'numolink': links },
954 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700955 sleep=sleep )
Jon Hall214f88b2020-09-21 10:21:42 -0700956 utilities.assert_equals( expect=main.TRUE, actual=topology,
957 onpass="Topology after link down is correct",
958 onfail="Topology after link down is incorrect" )
Jon Hall1efcb3f2016-08-23 13:42:15 -0700959
960 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700961 def killLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800962 """
963 links = list of links (src, dst) to bring down.
964 """
965
966 main.step("Killing a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700967 if sleep is None:
968 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
969 else:
970 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800971
972 for end1, end2 in links:
973 main.Network.link( END1=end1, END2=end2, OPTION="down")
974 main.Network.link( END1=end2, END2=end1, OPTION="down")
975
Jon Halla604fd42018-05-04 14:27:27 -0700976 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800977 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -0700978 "Waiting %s seconds for links down to be discovered" % sleep )
979 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800980
981 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
982 main.FALSE,
983 kwargs={ 'numoswitch': switches,
984 'numolink': linksAfter },
985 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -0700986 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800987
You Wang2854bce2018-03-30 10:15:32 -0700988 utilities.assert_equals( expect=main.TRUE, actual=topology,
989 onpass="Link batch down successful",
990 onfail="Link batch down failed" )
991
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800992 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -0700993 def restoreLinkBatch( main, links, linksAfter, switches, sleep=None ):
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -0800994 """
995 links = list of link (src, dst) to bring up again.
996 """
997
998 main.step("Restoring a batch of links {0}".format(links))
Jon Halla604fd42018-05-04 14:27:27 -0700999 if sleep is None:
1000 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
1001 else:
1002 sleep = float( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -08001003
1004 for end1, end2 in links:
1005 main.Network.link( END1=end1, END2=end2, OPTION="up")
1006 main.Network.link( END1=end2, END2=end1, OPTION="up")
1007
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -08001008 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -07001009 "Waiting %s seconds for links up to be discovered" % sleep )
1010 time.sleep( sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -08001011
1012 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
1013 main.FALSE,
1014 kwargs={ 'numoswitch': switches,
1015 'numolink': linksAfter },
1016 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -07001017 sleep=sleep )
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -08001018
You Wang2854bce2018-03-30 10:15:32 -07001019 utilities.assert_equals( expect=main.TRUE, actual=topology,
1020 onpass="Link batch up successful",
1021 onfail="Link batch up failed" )
1022
Andreas Pantelopoulosfab6bf32018-03-06 18:56:35 -08001023 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001024 def disablePortBatch( main, ports, switches=None, links=None, sleep=None ):
1025 """
1026 Disable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
1027 ports: a list of ports to disable ex. [ [ "of:0000000000000001", 1 ] ]
1028 switches, links: number of expected switches and links after link change, ex.: '4', '6'
1029 """
1030 if sleep is None:
1031 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
1032 else:
1033 sleep = float( sleep )
1034 main.step( "Disable a batch of ports" )
1035 for dpid, port in ports:
1036 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="disable" )
1037 main.log.info( "Waiting {} seconds for port down to be discovered".format( sleep ) )
1038 time.sleep( sleep )
1039 if switches and links:
1040 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
1041 numolink=links )
1042 utilities.assert_equals( expect=main.TRUE, actual=result,
1043 onpass="Port down successful",
1044 onfail="Port down failed" )
1045
1046 @staticmethod
1047 def enablePortBatch( main, ports, switches, links, sleep=None ):
1048 """
1049 Enable a list of switch ports using 'portstate' and verify ONOS can see the proper link change
1050 ports: a list of ports to enable ex. [ [ "of:0000000000000001", 1 ] ]
1051 switches, links: number of expected switches and links after link change, ex.: '4', '6'
1052 """
1053 if sleep is None:
1054 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
1055 else:
1056 sleep = float( sleep )
1057 main.step( "Enable a batch of ports" )
1058 for dpid, port in ports:
1059 main.Cluster.active( 0 ).CLI.portstate( dpid=dpid, port=port, state="enable" )
1060 main.log.info( "Waiting {} seconds for port up to be discovered".format( sleep ) )
1061 time.sleep( sleep )
1062 if switches and links:
1063 result = main.Cluster.active( 0 ).CLI.checkStatus( numoswitch=switches,
1064 numolink=links )
1065 utilities.assert_equals( expect=main.TRUE, actual=result,
1066 onpass="Port up successful",
1067 onfail="Port up failed" )
1068
1069 @staticmethod
You Wangc02d8352018-04-17 16:42:10 -07001070 def restoreLink( main, end1, end2, switches, links,
Jon Halla604fd42018-05-04 14:27:27 -07001071 portUp=False, dpid1='', dpid2='', port1='', port2='', sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001072 """
1073 Params:
1074 end1,end2: identify the end switches, ex.: 'leaf1', 'spine1'
You Wangc02d8352018-04-17 16:42:10 -07001075 portUp: enable portstate after restoring link
Jon Hall1efcb3f2016-08-23 13:42:15 -07001076 dpid1, dpid2: dpid of the end switches respectively, ex.: 'of:0000000000000002'
1077 port1, port2: respective port of the end switches that connects to the link, ex.:'1'
1078 switches, links: number of expected switches and links after linkDown, ex.: '4', '6'
1079 Kill a link and verify ONOS can see the proper link change
1080 """
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001081 main.step( "Restore link between %s and %s" % ( end1, end2 ) )
Jon Halla604fd42018-05-04 14:27:27 -07001082 if sleep is None:
1083 sleep = float( main.params[ 'timers' ][ 'LinkDiscovery' ] )
1084 else:
1085 sleep = float( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001086 result = False
1087 count = 0
1088 while True:
1089 count += 1
Jon Halla604fd42018-05-04 14:27:27 -07001090 ctrl = main.Cluster.next()
You Wangd5873482018-01-24 12:30:00 -08001091 main.Network.link( END1=end1, END2=end2, OPTION="up" )
1092 main.Network.link( END2=end1, END1=end2, OPTION="up" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001093 main.log.info(
Jon Halla604fd42018-05-04 14:27:27 -07001094 "Waiting %s seconds for link up to be discovered" % sleep )
1095 time.sleep( sleep )
Pierfb719b12016-09-19 14:51:44 -07001096
You Wangc02d8352018-04-17 16:42:10 -07001097 if portUp:
1098 ctrl.CLI.portstate( dpid=dpid1, port=port1, state='Enable' )
1099 ctrl.CLI.portstate( dpid=dpid2, port=port2, state='Enable' )
Jon Hall43060f62020-06-23 13:13:33 -07001100 main.log.info(
1101 "Waiting %s seconds for link up to be discovered" % sleep )
Jon Halla604fd42018-05-04 14:27:27 -07001102 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001103
Jon Halla604fd42018-05-04 14:27:27 -07001104 result = ctrl.CLI.checkStatus( numoswitch=switches,
1105 numolink=links )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001106 if count > 5 or result:
1107 break
1108 utilities.assert_equals( expect=main.TRUE, actual=result,
1109 onpass="Link up successful",
1110 onfail="Failed to bring link up" )
1111
1112 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001113 def killSwitch( main, switch, switches, links, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001114 """
1115 Params: switches, links: number of expected switches and links after SwitchDown, ex.: '4', '6'
1116 Completely kill a switch and verify ONOS can see the proper change
1117 """
Jon Halla604fd42018-05-04 14:27:27 -07001118 if sleep is None:
1119 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
1120 else:
1121 sleep = float( sleep )
You Wangc02d8352018-04-17 16:42:10 -07001122 switch = switch if isinstance( switch, list ) else [ switch ]
1123 main.step( "Kill " + str( switch ) )
1124 for s in switch:
1125 main.log.info( "Stopping " + s )
1126 main.Network.switch( SW=s, OPTION="stop" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001127 # todo make this repeatable
Jon Halla604fd42018-05-04 14:27:27 -07001128
1129 # TODO: Can remove this, since in the retry we will wait anyways if topology is incorrect
Jon Hall1efcb3f2016-08-23 13:42:15 -07001130 main.log.info( "Waiting %s seconds for switch down to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -07001131 sleep ) )
1132 time.sleep( sleep )
Devin Lim142b5342017-07-20 15:22:39 -07001133 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001134 main.FALSE,
1135 kwargs={ 'numoswitch': switches,
1136 'numolink': links },
1137 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -07001138 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001139 utilities.assert_equals( expect=main.TRUE, actual=topology,
1140 onpass="Kill switch successful",
1141 onfail="Failed to kill switch?" )
1142
1143 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001144 def recoverSwitch( main, switch, switches, links, rediscoverHosts=False, hostsToDiscover=[], sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001145 """
1146 Params: switches, links: number of expected switches and links after SwitchUp, ex.: '4', '6'
1147 Recover a switch and verify ONOS can see the proper change
1148 """
Jon Halla604fd42018-05-04 14:27:27 -07001149 if sleep is None:
1150 sleep = float( main.params[ 'timers' ][ 'SwitchDiscovery' ] )
1151 else:
1152 sleep = float( sleep )
1153 # TODO make this repeatable
You Wangc02d8352018-04-17 16:42:10 -07001154 switch = switch if isinstance( switch, list ) else [ switch ]
1155 main.step( "Recovering " + str( switch ) )
1156 for s in switch:
1157 main.log.info( "Starting " + s )
1158 main.Network.switch( SW=s, OPTION="start" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001159 main.log.info( "Waiting %s seconds for switch up to be discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -07001160 sleep ) )
1161 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -07001162 if rediscoverHosts:
You Wang48381752018-05-07 13:50:57 -07001163 main.Network.discoverHosts( hostList=hostsToDiscover )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -07001164 main.log.info( "Waiting %s seconds for hosts to get re-discovered" % (
Jon Halla604fd42018-05-04 14:27:27 -07001165 sleep ) )
1166 time.sleep( sleep )
Andreas Pantelopoulos74c7ff22018-05-01 15:42:02 -07001167
Devin Lim142b5342017-07-20 15:22:39 -07001168 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001169 main.FALSE,
1170 kwargs={ 'numoswitch': switches,
1171 'numolink': links },
1172 attempts=10,
Jon Halla604fd42018-05-04 14:27:27 -07001173 sleep=sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001174 utilities.assert_equals( expect=main.TRUE, actual=topology,
1175 onpass="Switch recovery successful",
1176 onfail="Failed to recover switch?" )
1177
Jonghwan Hyun25c98a62018-05-04 13:59:09 -07001178 @staticmethod
You Wang0f745de2018-07-27 15:49:22 -07001179 def killRouter( main, router, sleep=None ):
1180 """
1181 Kill bgpd process on a quagga router
1182 router: name of the router to be killed. E.g. "bgp1"
1183 """
1184 sleep = float( sleep )
1185 main.step( "Kill " + str( router ) )
1186 if hasattr( main, 'Mininet1' ):
1187 main.Mininet1.handle.sendline( "px {}.stopProtocols()".format( router ) )
1188 main.Mininet1.handle.expect( "mininet>" )
1189 else:
1190 # TODO: support killing router in physical network
1191 pass
1192 main.log.info( "Waiting %s seconds for router down to be discovered" % ( sleep ) )
1193 time.sleep( sleep )
1194
1195 @staticmethod
1196 def recoverRouter( main, router, sleep=None ):
1197 """
1198 Restart bgpd process on a quagga router
1199 router: name of the router to be recovered. E.g. "bgp1"
1200 """
1201 sleep = float( sleep )
1202 main.step( "Recovering " + str( router ) )
1203 if hasattr( main, 'Mininet1' ):
1204 main.Mininet1.handle.sendline( "px {}.startProtocols()".format( router ) )
1205 main.Mininet1.handle.expect( "mininet>" )
1206 else:
1207 # TODO: support recovering router in physical network
1208 pass
1209 main.log.info( "Waiting %s seconds for router up to be discovered" % ( sleep ) )
1210 time.sleep( sleep )
1211
1212 @staticmethod
You Wang5da39c82018-04-26 22:55:08 -07001213 def cleanup( main, copyKarafLog=True, removeHostComponent=False ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001214 """
1215 Stop Onos-cluster.
1216 Stops Mininet
1217 Copies ONOS log
1218 """
You Wang4cc61912018-08-28 10:10:58 -07001219 from tests.dependencies.utils import Utils
1220 main.utils = Utils()
Jon Hall627b1572020-12-01 12:01:15 -08001221 if not main.persistentSetup:
1222 for ctrl in main.Cluster.active():
1223 ctrl.CLI.log( "\"Ending Test - Shutting down ONOS and Network\"", level="INFO" )
You Wang4cc61912018-08-28 10:10:58 -07001224 # Clean up scapy hosts
You Wange24d6272018-03-27 21:18:50 -07001225 if hasattr( main, "scapyHosts" ):
1226 scapyResult = main.TRUE
1227 for host in main.scapyHosts:
1228 scapyResult = host.stopScapy() and scapyResult
1229 main.log.info( "Stopped Scapy Host: {0}".format( host.name ) )
1230 for host in main.scapyHosts:
You Wang4cc61912018-08-28 10:10:58 -07001231 if hasattr( main, 'Mininet1' ):
1232 scapyResult = main.Scapy.removeHostComponent( host.name ) and scapyResult
1233 else:
1234 scapyResult = main.Network.removeHostComponent( host.name ) and scapyResult
You Wange24d6272018-03-27 21:18:50 -07001235 main.log.info( "Removed Scapy Host Component: {0}".format( host.name ) )
1236 main.scapyHosts = []
1237
You Wang5da39c82018-04-26 22:55:08 -07001238 if removeHostComponent:
Jon Hall22a3bcf2021-07-23 11:40:11 -07001239 try:
1240 for host in main.internalIpv4Hosts + main.internalIpv6Hosts + main.externalIpv4Hosts + main.externalIpv6Hosts:
1241 if hasattr( main, host ):
1242 if hasattr( main, 'Mininet1' ):
1243 pass
1244 else:
1245 getattr( main, host ).disconnectInband()
1246 main.Network.removeHostComponent( host )
1247 except AttributeError as e:
1248 main.log.warn( "Could not cleanup host components: " + repr( e ) )
You Wang5da39c82018-04-26 22:55:08 -07001249
You Wang5df1c6d2018-04-06 18:02:02 -07001250 if hasattr( main, 'Mininet1' ):
Pier6a0c4de2018-03-18 16:01:30 -07001251 main.utils.mininetCleanup( main.Mininet1 )
You Wang4cc61912018-08-28 10:10:58 -07001252 else:
1253 main.Network.disconnectInbandHosts()
1254 main.Network.disconnectFromNet()
Devin Lim58046fa2017-07-05 16:55:00 -07001255
You Wang5df1c6d2018-04-06 18:02:02 -07001256 if copyKarafLog:
Jon Halldd05bbc2022-01-27 12:14:50 -08001257 useStern = strtobool( main.params.get( "use_stern", "False" ) )
1258 main.utils.copyKarafLog( "CASE%d" % main.CurrentTestCaseNumber, before=False,
1259 includeCaseDesc=False, useStern=useStern )
1260
1261 Testcaselib.saveOnosDiagsIfFailure( main )
Devin Lim58046fa2017-07-05 16:55:00 -07001262
Jon Hall627b1572020-12-01 12:01:15 -08001263 if not main.persistentSetup:
1264 for ctrl in main.Cluster.active():
1265 main.ONOSbench.onosStop( ctrl.ipAddress )
Jon Hall06fd0df2021-01-25 15:50:06 -08001266 else:
1267 Testcaselib.resetOnosLogLevels( main )
Jon Hall43060f62020-06-23 13:13:33 -07001268 Testcaselib.mnDockerTeardown( main )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001269
1270 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001271 def verifyNodes( main ):
1272 """
1273 Verifies Each active node in the cluster has an accurate view of other node's and their status
1274
1275 Params:
1276 nodes, integer array with position of the ONOS nodes in the CLIs array
1277 """
1278 nodeResults = utilities.retry( main.Cluster.nodesCheck,
1279 False,
1280 attempts=10,
1281 sleep=10 )
1282 utilities.assert_equals( expect=True, actual=nodeResults,
1283 onpass="Nodes check successful",
1284 onfail="Nodes check NOT successful" )
1285
1286 if not nodeResults:
1287 for ctrl in main.Cluster.runningNodes:
1288 main.log.debug( "{} components not ACTIVE: \n{}".format(
1289 ctrl.name,
Jon Hall6c9e2da2018-11-06 12:01:23 -08001290 ctrl.CLI.sendline( "onos:scr-list | grep -v ACTIVE" ) ) )
You Wang0bed5932018-12-11 14:45:41 -08001291 main.log.error( "Failed to verify nodes, stopping test" )
Jon Halla604fd42018-05-04 14:27:27 -07001292 main.cleanAndExit()
1293
1294 @staticmethod
Jon Hall39570262020-11-17 12:18:19 -08001295 def verifyTopology( main, switches, links, expNodes, SCCs=1 ):
Jon Halla604fd42018-05-04 14:27:27 -07001296 """
1297 Verifies that the ONOS cluster has an acuurate view of the topology
1298
1299 Params:
1300 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 -08001301 SCCs = Number of connected topology clusters within the control plane, defaults to 1
Jon Halla604fd42018-05-04 14:27:27 -07001302 """
1303 main.step( "Check number of topology elements" )
1304 topology = utilities.retry( main.Cluster.active( 0 ).CLI.checkStatus,
1305 main.FALSE,
1306 kwargs={ 'numoswitch': switches,
1307 'numolink': links,
Jon Hall39570262020-11-17 12:18:19 -08001308 'numoctrl': expNodes,
1309 'numoSCCs': SCCs },
Jon Halla604fd42018-05-04 14:27:27 -07001310 attempts=10,
1311 sleep=12 )
1312 utilities.assert_equals( expect=main.TRUE, actual=topology,
1313 onpass="Number of topology elements are correct",
Jon Hall39570262020-11-17 12:18:19 -08001314 onfail="Unexpected number of links, switches, and/or controllers: " + main.TOPOOUTPUT )
Jon Halla604fd42018-05-04 14:27:27 -07001315
1316 @staticmethod
1317 def killOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001318 """
1319 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1320 switches, links, nodes: number of expected switches, links and nodes after KillOnos, ex.: '4', '6'
1321 Completely Kill an ONOS instance and verify the ONOS cluster can see the proper change
1322 """
Jon Halla604fd42018-05-04 14:27:27 -07001323 # TODO: We have enough information in the Cluster instance to remove expNodes from here and verifyTopology
Jon Hall3c910162018-03-07 14:42:16 -08001324 main.step( "Killing ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001325 if sleep is None:
1326 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1327 else:
1328 sleep = float( sleep )
Pier3b58c652016-09-26 12:03:31 -07001329
Jon Hall214f88b2020-09-21 10:21:42 -07001330 stepResult = main.TRUE
Jon Hall1efcb3f2016-08-23 13:42:15 -07001331 for i in nodes:
Jon Hall214f88b2020-09-21 10:21:42 -07001332 node = main.Cluster.runningNodes[ i ]
1333 if node.inDocker:
1334 killResult = node.server.dockerStop( node.name )
1335 else:
1336 killResult = main.ONOSbench.onosDie( node.ipAddress )
1337 stepResult = stepResult and killResult
Devin Lim142b5342017-07-20 15:22:39 -07001338 main.Cluster.runningNodes[ i ].active = False
Jon Hall214f88b2020-09-21 10:21:42 -07001339 utilities.assert_equals( expect=main.TRUE, actual=stepResult,
1340 onpass="ONOS instance Killed",
1341 onfail="Error killing ONOS instance" )
Jon Halla604fd42018-05-04 14:27:27 -07001342 main.Cluster.reset()
Jon Hall43060f62020-06-23 13:13:33 -07001343 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001344 time.sleep( sleep )
Pier3b58c652016-09-26 12:03:31 -07001345
Devin Lim142b5342017-07-20 15:22:39 -07001346 if len( nodes ) < main.Cluster.numCtrls:
Jon Halla604fd42018-05-04 14:27:27 -07001347 Testcaselib.verifyNodes( main )
1348 Testcaselib.verifyTopology( main, switches, links, expNodes )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001349
1350 @staticmethod
Jon Halla604fd42018-05-04 14:27:27 -07001351 def recoverOnos( main, nodes, switches, links, expNodes, sleep=None ):
Jon Hall1efcb3f2016-08-23 13:42:15 -07001352 """
1353 Params: nodes, integer array with position of the ONOS nodes in the CLIs array
1354 switches, links, nodes: number of expected switches, links and nodes after recoverOnos, ex.: '4', '6'
1355 Recover an ONOS instance and verify the ONOS cluster can see the proper change
1356 """
Jon Hall3c910162018-03-07 14:42:16 -08001357 main.step( "Recovering ONOS instances with index(es): {}".format( nodes ) )
Jon Halla604fd42018-05-04 14:27:27 -07001358 if sleep is None:
1359 sleep = float( main.params[ 'timers' ][ 'OnosDiscovery' ] )
1360 else:
1361 sleep = float( sleep )
Jon Hall214f88b2020-09-21 10:21:42 -07001362 for i in nodes:
1363 node = main.Cluster.runningNodes[ i ]
1364 if node.inDocker:
1365 main.Cluster.startONOSDockerNode( i )
1366 else:
1367 main.ONOSbench.onosStart( node.ipAddress )
Jon Hall43060f62020-06-23 13:13:33 -07001368 main.log.debug( "sleeping %i seconds" % ( sleep ) )
Jon Halla604fd42018-05-04 14:27:27 -07001369 time.sleep( sleep )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001370 for i in nodes:
Jon Hall39570262020-11-17 12:18:19 -08001371 node = main.Cluster.runningNodes[ i ]
Jon Hall214f88b2020-09-21 10:21:42 -07001372 if node.inDocker:
1373 isUp = node.CLI.dockerExec( node.name, dockerPrompt=node.dockerPrompt )
1374 isUp = isUp and node.CLI.prepareForCLI()
1375 isUp = isUp and node.CLI.onosSecureSSH( userName=node.karafUser, userPWD=node.karafPass )
1376 else:
1377 isUp = main.ONOSbench.isup( node.ipAddress )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001378 utilities.assert_equals( expect=main.TRUE, actual=isUp,
1379 onpass="ONOS service is ready",
1380 onfail="ONOS service did not start properly" )
1381 for i in nodes:
1382 main.step( "Checking if ONOS CLI is ready" )
Devin Lim142b5342017-07-20 15:22:39 -07001383 ctrl = main.Cluster.runningNodes[ i ]
Jonghwan Hyun76a02b72018-01-30 16:40:48 +09001384 # ctrl.CLI.startCellCli()
Devin Lim142b5342017-07-20 15:22:39 -07001385 cliResult = ctrl.CLI.startOnosCli( ctrl.ipAddress,
1386 commandlineTimeout=60,
1387 onosStartTimeout=100 )
1388 ctrl.active = True
Jon Hall1efcb3f2016-08-23 13:42:15 -07001389 utilities.assert_equals( expect=main.TRUE,
1390 actual=cliResult,
1391 onpass="ONOS CLI is ready",
1392 onfail="ONOS CLI is not ready" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001393
Jon Halla604fd42018-05-04 14:27:27 -07001394 main.Cluster.reset()
Pier3b58c652016-09-26 12:03:31 -07001395 main.step( "Checking ONOS nodes" )
Jon Halla604fd42018-05-04 14:27:27 -07001396 Testcaselib.verifyNodes( main )
1397 Testcaselib.verifyTopology( main, switches, links, expNodes )
Pier3b58c652016-09-26 12:03:31 -07001398
Devin Lim142b5342017-07-20 15:22:39 -07001399 ready = utilities.retry( main.Cluster.active( 0 ).CLI.summary,
You Wang5bf49592020-07-08 18:47:46 -07001400 [ None, main.FALSE ],
Devin Lim142b5342017-07-20 15:22:39 -07001401 attempts=10,
1402 sleep=12 )
1403 if ready:
1404 ready = main.TRUE
1405 utilities.assert_equals( expect=main.TRUE, actual=ready,
Jon Hall1efcb3f2016-08-23 13:42:15 -07001406 onpass="ONOS summary command succeded",
1407 onfail="ONOS summary command failed" )
1408 if not ready:
1409 main.log.error( "ONOS startup failed!" )
Devin Lim44075962017-08-11 10:56:37 -07001410 main.cleanAndExit()
Jon Hall1efcb3f2016-08-23 13:42:15 -07001411
1412 @staticmethod
1413 def addHostCfg( main ):
1414 """
1415 Adds Host Configuration to ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001416 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001417 """
1418 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001419 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001420 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001421 hostCfg = json.load( template )
1422 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'in1' ]
1423 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001424 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001425 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1426 subjectClass="hosts",
1427 subjectKey=urllib.quote( mac,
1428 safe='' ),
1429 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001430 main.pingChart[ 'ip' ][ 'hosts' ] += [ 'out1' ]
1431 main.step( "Pushing new configuration" )
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001432 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001433 main.Cluster.active( 0 ).REST.setNetCfg( cfg[ 'basic' ],
1434 subjectClass="hosts",
1435 subjectKey=urllib.quote( mac,
1436 safe='' ),
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001437 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001438 main.pingChart.update( { 'vlan1': { "expect": "True",
1439 "hosts": [ "olt1", "vsg1" ] } } )
1440 main.pingChart[ 'vlan5' ][ 'expect' ] = 0
1441 main.pingChart[ 'vlan10' ][ 'expect' ] = 0
Jon Hall10e2ab82020-09-15 17:14:54 -07001442 main.Cluster.active( 0 ).REST.setXconnect( "of:0000000000000001",
1443 vlanId=1,
1444 port1=5,
1445 port2=6 )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001446
1447 @staticmethod
1448 def delHostCfg( main ):
1449 """
1450 Removest Host Configuration from ONOS
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001451 Updates expected state of the network ( pingChart )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001452 """
1453 import json
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001454 hostCfg = {}
Devin Lim57221b02018-02-14 15:45:36 -08001455 with open( main.configPath + main.forJson + "extra.json" ) as template:
Jon Hall1efcb3f2016-08-23 13:42:15 -07001456 hostCfg = json.load( template )
1457 main.step( "Removing host configuration" )
1458 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001459 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001460 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1461 subjectKey=urllib.quote(
1462 mac,
1463 safe='' ),
1464 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001465 main.step( "Removing configuration" )
1466 main.pingChart[ 'ip' ][ 'expect' ] = 0
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07001467 mac, cfg = hostCfg[ 'hosts' ].popitem()
Devin Lim142b5342017-07-20 15:22:39 -07001468 main.Cluster.active( 0 ).REST.removeNetCfg( subjectClass="hosts",
1469 subjectKey=urllib.quote(
1470 mac,
1471 safe='' ),
1472 configKey="basic" )
Jon Hall1efcb3f2016-08-23 13:42:15 -07001473 main.step( "Removing vlan configuration" )
1474 main.pingChart[ 'vlan1' ][ 'expect' ] = 0
Jon Hall10e2ab82020-09-15 17:14:54 -07001475 main.Cluster.active( 0 ).REST.deleteXconnect( "of:0000000000000001",
1476 vlanId=1 )
You Wang53dba1e2018-02-02 17:45:44 -08001477
1478 @staticmethod
1479 def verifyNetworkHostIp( main, attempts=10, sleep=10 ):
1480 """
1481 Verifies IP address assignment from the hosts
1482 """
1483 main.step( "Verify IP address assignment from hosts" )
1484 ipResult = main.TRUE
You Wangd66de192018-04-30 17:30:12 -07001485 main.Network.update()
You Wang6acb7a42018-05-04 15:12:25 -07001486 # Find out names of disconnected hosts
1487 disconnectedHosts = []
1488 if hasattr( main, "disconnectedIpv4Hosts" ):
1489 for host in main.disconnectedIpv4Hosts:
1490 disconnectedHosts.append( host )
1491 if hasattr( main, "disconnectedIpv6Hosts" ):
1492 for host in main.disconnectedIpv6Hosts:
1493 disconnectedHosts.append( host )
You Wang53dba1e2018-02-02 17:45:44 -08001494 for hostName, ip in main.expectedHosts[ "network" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001495 # Exclude disconnected hosts
1496 if hostName in disconnectedHosts:
1497 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( hostName ) )
1498 continue
You Wang53dba1e2018-02-02 17:45:44 -08001499 ipResult = ipResult and utilities.retry( main.Network.verifyHostIp,
1500 main.FALSE,
1501 kwargs={ 'hostList': [ hostName ],
You Wangd66de192018-04-30 17:30:12 -07001502 'prefix': ip,
Jon Hall43060f62020-06-23 13:13:33 -07001503 'update': True },
You Wang53dba1e2018-02-02 17:45:44 -08001504 attempts=attempts,
1505 sleep=sleep )
1506 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1507 onpass="Verify network host IP succeded",
1508 onfail="Verify network host IP failed" )
1509
1510 @staticmethod
You Wangaec6a092018-08-06 15:36:31 -07001511 def verifyOnosHostIp( main, attempts=10, sleep=10, skipOnFail=True ):
You Wang53dba1e2018-02-02 17:45:44 -08001512 """
1513 Verifies host IP address assignment from ONOS
1514 """
1515 main.step( "Verify host IP address assignment in ONOS" )
1516 ipResult = main.TRUE
You Wang6acb7a42018-05-04 15:12:25 -07001517 # Find out IPs of disconnected hosts
1518 disconnectedIps = []
1519 if hasattr( main, "disconnectedIpv4Hosts" ):
1520 for host in main.disconnectedIpv4Hosts:
1521 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
1522 if hasattr( main, "disconnectedIpv6Hosts" ):
1523 for host in main.disconnectedIpv6Hosts:
1524 disconnectedIps.append( main.expectedHosts[ "network" ][ host ] )
You Wang53dba1e2018-02-02 17:45:44 -08001525 for hostName, ip in main.expectedHosts[ "onos" ].items():
You Wang6acb7a42018-05-04 15:12:25 -07001526 # Exclude disconnected hosts
1527 if ip in disconnectedIps:
1528 main.log.debug( "Skip verifying IP for {} as it's disconnected".format( ip ) )
1529 continue
You Wang53dba1e2018-02-02 17:45:44 -08001530 ipResult = ipResult and utilities.retry( main.Cluster.active( 0 ).verifyHostIp,
1531 main.FALSE,
1532 kwargs={ 'hostList': [ hostName ],
1533 'prefix': ip },
1534 attempts=attempts,
1535 sleep=sleep )
1536 utilities.assert_equals( expect=main.TRUE, actual=ipResult,
1537 onpass="Verify ONOS host IP succeded",
1538 onfail="Verify ONOS host IP failed" )
You Wangaec6a092018-08-06 15:36:31 -07001539 if not ipResult and skipOnFail:
You Wang89477152018-08-07 14:19:02 -07001540 Testcaselib.cleanup( main, copyKarafLog=False )
You Wangaec6a092018-08-06 15:36:31 -07001541 main.skipCase()
Andreas Pantelopoulos2eae3242018-03-06 13:47:20 -08001542
Jonghwan Hyun812c70f2018-02-16 16:33:16 -08001543 @staticmethod
1544 def updateIntfCfg( main, connectPoint, ips=[], untagged=0, tagged=[], native=0 ):
1545 """
1546 Description:
1547 Updates interface configuration in ONOS, with given IP and vlan parameters
1548 Required:
1549 * connectPoint: connect point to update configuration
1550 Optional:
1551 * ips: list of IP addresses, combined with '/xx' subnet representation,
1552 corresponding to 'ips' field in the configuration
1553 * untagged: vlan ID as an integer, corresponding to 'vlan-untagged' field in the configuration
1554 * tagged: integer list of vlan IDs, corresponding to 'vlan-tagged' field in the configuration
1555 * native: vlan ID as an integer, corresponding to 'vlan-native' field in the configuration
1556 """
1557 cfg = dict()
1558 cfg[ "ports" ] = dict()
1559 cfg[ "ports" ][ connectPoint ] = dict()
1560 cfg[ "ports" ][ connectPoint ][ "interfaces" ] = [ dict() ]
1561 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "ips" ] = ips
1562 if untagged > 0:
1563 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-untagged" ] = untagged
1564 else:
1565 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-tagged" ] = tagged
1566 if native > 0:
1567 cfg[ "ports" ][ connectPoint ][ "interfaces" ][ 0 ][ "vlan-native" ] = native
1568
1569 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( json.dumps( cfg ) ) )
You Wange24d6272018-03-27 21:18:50 -07001570
1571 @staticmethod
You Wang2cb70172018-07-25 16:44:13 -07001572 def startScapyHosts( main, scapyNames=[], mininetNames=[] ):
You Wange24d6272018-03-27 21:18:50 -07001573 """
1574 Create host components and start Scapy CLIs
You Wang2cb70172018-07-25 16:44:13 -07001575 scapyNames: list of names that will be used as component names for scapy hosts
1576 mininetNames: used when scapy host names are different from the host names
1577 in Mininet. E.g. when scapyNames=['h1Scapy'], it's required to specify the
1578 name of the corresponding Mininet host by mininetNames=['h1']
You Wange24d6272018-03-27 21:18:50 -07001579 """
1580 main.step( "Start Scapy CLIs" )
You Wang4cc61912018-08-28 10:10:58 -07001581 main.scapyNames = scapyNames if scapyNames else main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
1582 main.scapyHosts = [] if not hasattr( main, "scapyHosts" ) else main.scapyHosts
You Wang2cb70172018-07-25 16:44:13 -07001583 for scapyName in main.scapyNames:
You Wang4cc61912018-08-28 10:10:58 -07001584 if hasattr( main, 'Mininet1' ):
1585 main.Scapy.createHostComponent( scapyName )
1586 scapyHandle = getattr( main, scapyName )
1587 if mininetNames:
1588 mininetName = mininetNames[ scapyNames.index( scapyName ) ]
1589 else:
1590 mininetName = None
Jon Hall43060f62020-06-23 13:13:33 -07001591 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
1592 scapyHandle.mExecDir = "/tmp"
1593 scapyHandle.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1594 main.log.debug( "start mn host component in docker" )
1595 scapyHandle.startHostCli( mininetName,
1596 execDir="/tmp",
1597 hostHome=main.params[ "MN_DOCKER" ][ "home" ] )
1598 else:
1599 main.log.debug( "start mn host component" )
1600 scapyHandle.startHostCli( mininetName )
You Wang2cb70172018-07-25 16:44:13 -07001601 else:
You Wang0fc21702018-11-02 17:49:18 -07001602 main.Network.createHostComponent( scapyName )
You Wang4cc61912018-08-28 10:10:58 -07001603 scapyHandle = getattr( main, scapyName )
1604 scapyHandle.connectInband()
1605 main.scapyHosts.append( scapyHandle )
You Wang2cb70172018-07-25 16:44:13 -07001606 scapyHandle.startScapy()
1607 scapyHandle.updateSelf()
1608 main.log.debug( scapyHandle.name )
1609 main.log.debug( scapyHandle.hostIp )
1610 main.log.debug( scapyHandle.hostMac )
1611
1612 @staticmethod
1613 def verifyTraffic( main, srcHosts, dstIp, dstHost, dstIntf, ipv6=False, expect=True, skipOnFail=True, maxRetry=2 ):
1614 """
1615 Verify unicast traffic by pinging from source hosts to the destination IP
1616 and capturing the packets at the destination host using Scapy.
1617 srcHosts: List of host names to send the ping packets
1618 dstIp: destination IP of the ping packets
1619 dstHost: host that runs Scapy to capture the packets
1620 dstIntf: name of the interface on the destination host
1621 expect: use True if the ping is expected to be captured at destination;
1622 Otherwise False
1623 skipOnFail: skip the rest of this test case if result is not expected
1624 maxRetry: number of retries allowed
1625 """
1626 from tests.dependencies.topology import Topology
1627 try:
1628 main.topo
1629 except ( NameError, AttributeError ):
1630 main.topo = Topology()
1631 main.step( "Verify traffic to {} by capturing packets on {}".format( dstIp, dstHost ) )
1632 result = main.TRUE
1633 for srcHost in srcHosts:
1634 trafficResult = main.topo.pingAndCapture( srcHost, dstIp, dstHost, dstIntf, ipv6,
1635 expect, maxRetry, True )
1636 if not trafficResult:
You Wang2cb70172018-07-25 16:44:13 -07001637 result = main.FALSE
1638 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcHost, dstIp ) )
1639 utilities.assert_equals( expect=main.TRUE,
1640 actual=result,
1641 onpass="Verify traffic to {}: Pass".format( dstIp ),
1642 onfail="Verify traffic to {}: Fail".format( dstIp ) )
1643 if skipOnFail and result != main.TRUE:
You Wang2cb70172018-07-25 16:44:13 -07001644 Testcaselib.cleanup( main, copyKarafLog=False )
1645 main.skipCase()
You Wange24d6272018-03-27 21:18:50 -07001646
1647 @staticmethod
You Wang547893e2018-05-08 13:34:59 -07001648 def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=1 ):
You Wange24d6272018-03-27 21:18:50 -07001649 """
1650 Verify multicast traffic using scapy
1651 """
You Wangc564c6f2018-05-01 15:24:57 -07001652 from tests.dependencies.topology import Topology
1653 try:
1654 main.topo
1655 except ( NameError, AttributeError ):
1656 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001657 main.step( "Verify {} multicast traffic".format( routeName ) )
You Wangc02d8352018-04-17 16:42:10 -07001658 routeData = main.multicastConfig[ routeName ]
1659 srcs = main.mcastRoutes[ routeName ][ "src" ]
1660 dsts = main.mcastRoutes[ routeName ][ "dst" ]
1661 main.log.info( "Sending multicast traffic from {} to {}".format( [ routeData[ "src" ][ i ][ "host" ] for i in srcs ],
1662 [ routeData[ "dst" ][ i ][ "host" ] for i in dsts ] ) )
You Wang85747762018-05-11 15:51:50 -07001663 result = main.TRUE
You Wangc02d8352018-04-17 16:42:10 -07001664 for src in srcs:
1665 srcEntry = routeData[ "src" ][ src ]
1666 for dst in dsts:
1667 dstEntry = routeData[ "dst" ][ dst ]
1668 sender = getattr( main, srcEntry[ "host" ] )
1669 receiver = getattr( main, dstEntry[ "host" ] )
1670 main.Network.addRoute( str( srcEntry[ "host" ] ),
1671 str( routeData[ "group" ] ),
1672 str( srcEntry[ "interface" ] ),
1673 True if routeData[ "ipVersion" ] == 6 else False )
1674 # Build the packet
1675 sender.buildEther( dst=str( srcEntry[ "Ether" ] ) )
1676 if routeData[ "ipVersion" ] == 4:
1677 sender.buildIP( dst=str( routeData[ "group" ] ) )
1678 elif routeData[ "ipVersion" ] == 6:
1679 sender.buildIPv6( dst=str( routeData[ "group" ] ) )
1680 sender.buildUDP( ipVersion=routeData[ "ipVersion" ], dport=srcEntry[ "UDP" ] )
1681 sIface = srcEntry[ "interface" ]
1682 dIface = dstEntry[ "interface" ] if "interface" in dstEntry.keys() else None
1683 pktFilter = srcEntry[ "filter" ]
1684 pkt = srcEntry[ "packet" ]
1685 # Send packet and check received packet
1686 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
You Wangc564c6f2018-05-01 15:24:57 -07001687 t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
Jon Halla604fd42018-05-04 14:27:27 -07001688 routeData[ "group" ], srcEntry[ "Ether" ] )
You Wangc564c6f2018-05-01 15:24:57 -07001689 trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
1690 expectedResult, maxRetry, True, t3Cmd )
You Wang85747762018-05-11 15:51:50 -07001691 if not trafficResult:
1692 result = main.FALSE
1693 main.log.warn( "Scapy result from {} to {} is not as expected".format( srcEntry[ "host" ],
1694 dstEntry[ "host" ] ) )
1695 utilities.assert_equals( expect=main.TRUE,
1696 actual=result,
1697 onpass="Verify {} multicast traffic: Pass".format( routeName ),
1698 onfail="Verify {} multicast traffic: Fail".format( routeName ) )
You Wangba823f02018-05-17 13:54:08 -07001699 if skipOnFail and result != main.TRUE:
You Wang85747762018-05-11 15:51:50 -07001700 Testcaselib.cleanup( main, copyKarafLog=False )
1701 main.skipCase()
You Wangc02d8352018-04-17 16:42:10 -07001702
1703 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001704 def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1,
You Wang54b1d672018-06-11 16:44:13 -07001705 acceptableFailed=0, skipOnFail=True, stepMsg="Verify Ping",
1706 t3Simple=True ):
You Wang5da39c82018-04-26 22:55:08 -07001707 """
1708 Verify reachability from each host in srcList to each host in dstList
1709 """
1710 from tests.dependencies.topology import Topology
1711 try:
1712 main.topo
1713 except ( NameError, AttributeError ):
1714 main.topo = Topology()
You Wang85747762018-05-11 15:51:50 -07001715 main.step( stepMsg )
You Wang54b1d672018-06-11 16:44:13 -07001716 pingResult = main.topo.ping( srcList, dstList, ipv6, expect, wait, acceptableFailed, skipOnFail, t3Simple )
You Wang85747762018-05-11 15:51:50 -07001717 utilities.assert_equals( expect=main.TRUE,
1718 actual=pingResult,
1719 onpass="{}: Pass".format( stepMsg ),
1720 onfail="{}: Fail".format( stepMsg ) )
You Wang5da39c82018-04-26 22:55:08 -07001721 if not pingResult and skipOnFail:
You Wang5da39c82018-04-26 22:55:08 -07001722 Testcaselib.cleanup( main, copyKarafLog=False, removeHostComponent=True )
1723 main.skipCase()
You Wangbc898b82018-05-03 16:22:34 -07001724
1725 @staticmethod
You Wang85747762018-05-11 15:51:50 -07001726 def verifyHostLocations( main, locationDict, retry=2 ):
You Wangbc898b82018-05-03 16:22:34 -07001727 """
1728 Verify if the specified host is discovered by ONOS on the given locations
1729 Required:
You Wang85747762018-05-11 15:51:50 -07001730 locationDict: a dictionary that maps host names to expected locations.
1731 locations could be a string or a list.
1732 ex. { "h1v4": ["of:0000000000000005/8"] }
You Wangbc898b82018-05-03 16:22:34 -07001733 Returns:
1734 main.TRUE if host is discovered on all locations provided, otherwise main.FALSE
1735 """
You Wang85747762018-05-11 15:51:50 -07001736 main.step( "Verify locations of hosts {}".format( locationDict.keys() ) )
1737 result = main.TRUE
1738 for hostName, locations in locationDict.items():
1739 main.log.info( "Verify host {} is discovered at {}".format( hostName, locations ) )
1740 hostIp = main.Network.getIPAddress( hostName, proto='IPV4' )
1741 if not hostIp:
1742 hostIp = main.Network.getIPAddress( hostName, proto='IPV6' )
1743 if not hostIp:
1744 main.log.warn( "Failed to find IP address for host {}, skipping location verification".format( hostName ) )
1745 result = main.FALSE
1746 continue
1747 locationResult = utilities.retry( main.Cluster.active( 0 ).CLI.verifyHostLocation,
1748 main.FALSE,
1749 args=( hostIp, locations ),
1750 attempts=retry + 1,
1751 sleep=10 )
1752 if not locationResult:
1753 result = main.FALSE
1754 main.log.warn( "location verification for host {} failed".format( hostName ) )
You Wang547893e2018-05-08 13:34:59 -07001755 utilities.assert_equals( expect=main.TRUE, actual=result,
You Wang85747762018-05-11 15:51:50 -07001756 onpass="Location verification passed",
1757 onfail="Location verification failed" )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001758
1759 @staticmethod
You Wang6e5b48e2018-07-23 16:17:38 -07001760 def moveHost( main, hostName, srcSw, dstSw, gw, macAddr=None, prefixLen=None, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001761 """
1762 Move specified host from srcSw to dstSw.
1763 If srcSw and dstSw are same, the host will be moved from current port to
1764 next available port.
1765 Required:
1766 hostName: name of the host. e.g., "h1"
1767 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1768 dstSw: name of the switch that the host will be moved to. e.g., "leaf2"
1769 gw: ip address of the gateway of the new location
1770 Optional:
1771 macAddr: if specified, change MAC address of the host to the specified MAC address.
1772 prefixLen: prefix length
1773 cfg: port configuration as JSON string
1774 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001775 vlan: vlan number of the host
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001776 """
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001777 if not hasattr( main, 'Mininet1' ):
1778 main.log.warn( "moveHost is supposed to be used only in Mininet." )
1779 return
1780
You Wang6e5b48e2018-07-23 16:17:38 -07001781 main.step( "Moving {} host {} from {} to {}".format( 'tagged' if vlan else 'untagged', hostName, srcSw, dstSw ) )
1782 main.Mininet1.moveHost( hostName, srcSw, dstSw, macAddr, prefixLen, ipv6, vlan=vlan )
1783 if not ipv6:
You Wang6260ed52018-07-18 17:54:25 -07001784 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001785 if cfg:
1786 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1787 subjectClass="ports" )
You Wang6260ed52018-07-18 17:54:25 -07001788 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001789 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang6260ed52018-07-18 17:54:25 -07001790 time.sleep( 5 )
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001791
1792 main.Mininet1.discoverHosts( [ hostName, ] )
1793
1794 # Update expectedHost when MAC address is changed.
1795 if macAddr is not None:
1796 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1797 if ipAddr is not None:
1798 for hostName, ip in main.expectedHosts[ "onos" ].items():
1799 if ip == ipAddr:
1800 vlan = hostName.split( "/" )[ -1 ]
1801 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001802 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jonghwan Hyun785471d2018-05-14 14:48:19 -07001803 break
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001804
1805 @staticmethod
1806 def moveDualHomedHost( main, hostName, srcSw, srcPairSw, dstSw, dstPairSw, gw,
You Wang6e5b48e2018-07-23 16:17:38 -07001807 macAddr=None, prefixLen=24, cfg='', ipv6=False, vlan=None ):
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001808 """
1809 Move specified dual-homed host from srcSw-srcPairSw to dstSw-dstPairSw.
1810 If srcSw-srcPairSw and dstSw-dstPairSw are same, the host will be moved from current port
1811 to next available port.
1812 Required:
1813 hostName: name of the host. e.g., "h1"
1814 srcSw: name of the switch that the host is attached to. e.g., "leaf1"
1815 srcPairSw: name of the paired-switch that the host is attached to. e.g., "leaf2"
1816 dstSw: name of the switch that the host will be moved to. e.g., "leaf1"
1817 dstPairSw: name of the paired-switch that the host will be moved to. e.g., "leaf2"
1818 gw: ip address of the gateway of the new location
1819 Optional:
1820 macAddr: if specified, change MAC address of the host to the specified MAC address.
1821 prefixLen: prefix length
1822 cfg: port configurations as JSON string
You Wang7ea90582018-07-19 15:27:58 -07001823 ipv6: Use True to move IPv6 host
You Wang6e5b48e2018-07-23 16:17:38 -07001824 vlan: vlan number of the host
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001825 """
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001826 if not hasattr( main, 'Mininet1' ):
1827 main.log.warn( "moveDualHomedHost is supposed to be used only in Mininet." )
1828 return
1829
You Wang6e5b48e2018-07-23 16:17:38 -07001830 main.step( "Moving {} host {} from {} and {} to {} and {}".format( 'tagged' if vlan else 'untagged', hostName,
1831 srcSw, srcPairSw, dstSw, dstPairSw ) )
1832 main.Mininet1.moveDualHomedHost( hostName, srcSw, srcPairSw, dstSw, dstPairSw,
1833 macAddr=macAddr, prefixLen=prefixLen, ipv6=ipv6, vlan=vlan )
1834 if not ipv6:
You Wang7ea90582018-07-19 15:27:58 -07001835 main.Mininet1.changeDefaultGateway( hostName, gw )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001836 if cfg:
1837 main.Cluster.active( 0 ).REST.setNetCfg( json.loads( cfg ),
1838 subjectClass="ports" )
You Wang7ea90582018-07-19 15:27:58 -07001839 # Wait for the host to get RA for setting up default gateway
Jon Hall43060f62020-06-23 13:13:33 -07001840 main.log.debug( "sleeping %i seconds" % ( 5 ) )
You Wang7ea90582018-07-19 15:27:58 -07001841 time.sleep( 5 )
Jonghwan Hyun5fad1782018-05-21 14:11:16 -07001842
1843 main.Mininet1.discoverHosts( [ hostName, ] )
1844
1845 # Update expectedHost when MAC address is changed.
1846 if macAddr is not None:
1847 ipAddr = main.expectedHosts[ "network" ][ hostName ]
1848 if ipAddr is not None:
1849 for hostName, ip in main.expectedHosts[ "onos" ].items():
1850 if ip == ipAddr:
1851 vlan = hostName.split( "/" )[ -1 ]
1852 del main.expectedHosts[ "onos" ][ hostName ]
You Wang7ea90582018-07-19 15:27:58 -07001853 main.expectedHosts[ "onos" ][ "{}/{}".format( macAddr.upper(), vlan ) ] = ip
Jon Hall43060f62020-06-23 13:13:33 -07001854
1855 @staticmethod
1856 def mnDockerSetup( main ):
1857 """
1858 Optionally start and setup docker image for mininet
1859 """
Jon Hall9b0de1f2020-08-24 15:38:04 -07001860 try:
1861 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall43060f62020-06-23 13:13:33 -07001862
Jon Hall9b0de1f2020-08-24 15:38:04 -07001863 main.log.info( "Creating Mininet Docker" )
1864 handle = main.Mininet1.handle
1865 # build docker image
1866 dockerFilePath = "%s/../dependencies/" % main.testDir
1867 dockerName = "trellis_mininet"
1868 # Stop any leftover container
1869 main.Mininet1.dockerStop( dockerName )
1870 # TODO: assert on these docker calls
Jon Hall39570262020-11-17 12:18:19 -08001871 main.Mininet1.dockerBuild( dockerFilePath, dockerName, pull=True )
Jon Hallf6aeda22020-07-28 09:12:56 -07001872
Jon Hall9b0de1f2020-08-24 15:38:04 -07001873 confDir = "/tmp/mn_conf/"
1874 # Try to ensure the destination exists
1875 main.log.info( "Create folder for network config files" )
1876 handle.sendline( "rm -rf %s" % confDir )
1877 handle.expect( main.Mininet1.Prompt() )
1878 main.log.debug( handle.before + handle.after )
1879 handle.sendline( "mkdir -p %s" % confDir )
1880 handle.expect( main.Mininet1.Prompt() )
1881 main.log.debug( handle.before + handle.after )
Jon Hall39570262020-11-17 12:18:19 -08001882 handle.sendline( "sudo rm -rf /tmp/mn-stratum/*" )
1883 handle.expect( main.Mininet1.Prompt() )
Jon Hall9b0de1f2020-08-24 15:38:04 -07001884 # Make sure permissions are correct
1885 handle.sendline( "sudo chown %s:%s %s" % ( main.Mininet1.user_name, main.Mininet1.user_name, confDir ) )
1886 handle.expect( main.Mininet1.Prompt() )
1887 handle.sendline( "sudo chmod -R a+rwx %s" % ( confDir ) )
1888 handle.expect( main.Mininet1.Prompt() )
1889 main.log.debug( handle.before + handle.after )
1890 # Start docker container
1891 runResponse = main.Mininet1.dockerRun( main.params[ 'MN_DOCKER' ][ 'name' ],
1892 dockerName,
1893 main.params[ 'MN_DOCKER' ][ 'args' ] )
1894 if runResponse == main.FALSE:
1895 main.log.error( "Docker container already running, aborting test" )
1896 main.cleanup()
1897 main.exit()
Jon Hall43060f62020-06-23 13:13:33 -07001898
Jon Hall9b0de1f2020-08-24 15:38:04 -07001899 main.Mininet1.dockerAttach( dockerName, dockerPrompt='~#' )
1900 main.Mininet1.sudoRequired = False
Jon Hall43060f62020-06-23 13:13:33 -07001901
Jon Hall9b0de1f2020-08-24 15:38:04 -07001902 # Fow when we create component handles
1903 main.Mininet1.mExecDir = "/tmp"
1904 main.Mininet1.hostHome = main.params[ "MN_DOCKER" ][ "home" ]
1905 main.Mininet1.hostPrompt = "/home/root#"
1906
1907 # For some reason docker isn't doing this
1908 main.Mininet1.handle.sendline( "echo \"127.0.0.1 $(cat /etc/hostname)\" >> /etc/hosts" )
1909 main.Mininet1.handle.expect( "etc/hosts" )
1910 main.Mininet1.handle.expect( main.Mininet1.Prompt() )
1911 except Exception as e:
1912 main.log.exception( "Error seting up mininet" )
Jon Hall39570262020-11-17 12:18:19 -08001913 main.skipCase( result="FAIL", msg=e )
Jon Hall43060f62020-06-23 13:13:33 -07001914
1915 @staticmethod
1916 def mnDockerTeardown( main ):
1917 """
1918 Optionally stop and cleanup docker image for mininet
1919 """
1920
1921 if hasattr( main, 'Mininet1' ):
1922 if 'MN_DOCKER' in main.params and main.params['MN_DOCKER']['args']:
Jon Hall3c0114c2020-08-11 15:07:42 -07001923 main.log.info( "Exiting from Mininet Docker" )
Jon Hall43060f62020-06-23 13:13:33 -07001924
1925 # Detach from container
Jon Hall43060f62020-06-23 13:13:33 -07001926 try:
Jon Hall3c0114c2020-08-11 15:07:42 -07001927 main.Mininet1.dockerDisconnect()
Jon Hall43060f62020-06-23 13:13:33 -07001928 main.Mininet1.sudoRequired = True
1929 except Exception as e:
1930 main.log.error( e )
1931
Jon Hall39570262020-11-17 12:18:19 -08001932 # Save docker logs
1933 copyResult = main.ONOSbench.scp( main.Mininet1,
1934 "/tmp/mn-stratum/*",
1935 main.logdir,
1936 direction="from",
1937 options="-rp" )
1938
1939
Jon Hall43060f62020-06-23 13:13:33 -07001940 @staticmethod
1941 def setOnosConfig( main ):
1942 """
1943 Read and Set onos configurations from the params file
1944 """
1945 main.step( "Set ONOS configurations" )
1946 config = main.params.get( 'ONOS_Configuration' )
1947 if config:
1948 main.log.debug( config )
1949 checkResult = main.TRUE
1950 for component in config:
1951 for setting in config[ component ]:
1952 value = config[ component ][ setting ]
1953 check = main.Cluster.next().setCfg( component, setting, value )
1954 main.log.info( "Value was changed? {}".format( main.TRUE == check ) )
1955 checkResult = check and checkResult
1956 utilities.assert_equals( expect=main.TRUE,
1957 actual=checkResult,
1958 onpass="Successfully set config",
1959 onfail="Failed to set config" )
1960 else:
1961 main.log.warn( "No configurations were specified to be changed after startup" )
1962
1963 @staticmethod
1964 def setOnosLogLevels( main ):
1965 """
1966 Read and Set onos log levels from the params file
1967 """
1968 main.step( 'Set logging levels' )
Jon Hall06fd0df2021-01-25 15:50:06 -08001969 # Get original values incase we want to reset them
1970 ctrl = main.Cluster.active(0)
Jon Halla7b27e62021-06-29 12:13:51 -07001971 ctrl.CLI.clearBuffer( timeout=1 )
Jon Hall06fd0df2021-01-25 15:50:06 -08001972 ctrl.CLI.logList()
1973
Jon Hall43060f62020-06-23 13:13:33 -07001974 logging = True
1975 try:
1976 logs = main.params.get( 'ONOS_Logging', False )
1977 if logs:
1978 for namespace, level in logs.items():
1979 for ctrl in main.Cluster.active():
1980 ctrl.CLI.logSet( level, namespace )
1981 except AttributeError:
1982 logging = False
1983 utilities.assert_equals( expect=True, actual=logging,
1984 onpass="Set log levels",
1985 onfail="Failed to set log levels" )
Jon Hall06fd0df2021-01-25 15:50:06 -08001986
1987 @staticmethod
1988 def resetOnosLogLevels( main ):
1989 """
1990 Read and reset onos log levels to a previously read set of values
1991 """
1992 main.step( 'Reset logging levels' )
1993 # Get original values incase we want to reset them
1994 ctrl = main.Cluster.active(0)
Jon Halla7b27e62021-06-29 12:13:51 -07001995 ctrl.CLI.clearBuffer( timeout=1 )
Jon Hall06fd0df2021-01-25 15:50:06 -08001996 currentLevels = ctrl.CLI.logList( saveValues=False )
1997 origLevels = ctrl.CLI.logLevels
1998 toBeSet = {}
1999 for logger, level in currentLevels.iteritems():
2000 if logger not in origLevels:
2001 toBeSet[ logger ] = origLevels[ 'ROOT' ]
2002 else:
2003 oldLevel = origLevels[ logger ]
2004 if level != oldLevel:
2005 toBeSet[ logger ] = oldLevel
Jon Hallef1480b2021-03-31 13:37:41 -07002006 # In case a previous test didn't reset
2007 logs = main.params.get( 'ONOS_Logging_Reset', False )
2008 if logs:
2009 for namespace, level in logs.items():
2010 toBeSet[ namespace ] = level
Jon Hall06fd0df2021-01-25 15:50:06 -08002011 logging = True
2012 try:
2013 for logger, level in toBeSet.iteritems():
2014 for ctrl in main.Cluster.active():
2015 ctrl.CLI.logSet( level, logger )
2016 except AttributeError:
2017 logging = False
2018 utilities.assert_equals( expect=True, actual=logging,
2019 onpass="Reset log levels",
2020 onfail="Failed to reset log levels" )
Daniele Moroc99bf822021-10-11 23:21:15 +02002021
2022 @staticmethod
2023 def saveOnosDiagsIfFailure( main ):
2024 if main.FALSE in main.stepResultsList:
2025 # Some step has failed
2026 Testcaselib.saveOnosDiagnostics( main )