blob: 70274089b2bedb3d66994b7ffa1cdeff51db1093 [file] [log] [blame]
Jon Hallfc915882015-07-14 13:33:17 -07001#!/usr/bin/env python
2"""
3Created on 07-08-2015
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00004Copyright 2015 Open Networking Foundation (ONF)
Jeremy Songsterae01bba2016-07-11 15:39:17 -07005
6Please refer questions to either the onos test mailing list at <onos-test@onosproject.org>,
7the System Testing Plans and Results wiki page at <https://wiki.onosproject.org/x/voMg>,
8or the System Testing Guide page at <https://wiki.onosproject.org/x/WYQg>
Jon Hallfc915882015-07-14 13:33:17 -07009
10 TestON is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 2 of the License, or
13 ( at your option ) any later version.
14
15 TestON is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with TestON. If not, see <http://www.gnu.org/licenses/>.
22
23"""
24import json
25import os
26import requests
kelvin-onlab03eb88d2015-07-22 10:29:02 -070027import types
Jon Halle401b092015-09-23 13:34:24 -070028import sys
Jon Hall3c0114c2020-08-11 15:07:42 -070029import time
Jon Hallfc915882015-07-14 13:33:17 -070030
Jon Hallfc915882015-07-14 13:33:17 -070031from drivers.common.api.controllerdriver import Controller
32
33
34class OnosRestDriver( Controller ):
35
36 def __init__( self ):
Jon Hallf7234882015-08-28 13:16:31 -070037 self.pwd = None
38 self.user_name = "user"
Devin Limdc78e202017-06-09 18:30:07 -070039 super( OnosRestDriver, self ).__init__()
Jon Hallfc915882015-07-14 13:33:17 -070040 self.ip_address = "localhost"
41 self.port = "8080"
Jon Halle401b092015-09-23 13:34:24 -070042 self.wrapped = sys.modules[ __name__ ]
Jon Hallfc915882015-07-14 13:33:17 -070043
44 def connect( self, **connectargs ):
45 try:
46 for key in connectargs:
47 vars( self )[ key ] = connectargs[ key ]
48 self.name = self.options[ 'name' ]
49 except Exception as e:
50 main.log.exception( e )
51 try:
Jeremy Ronquillo82705492017-10-18 14:19:55 -070052 if os.getenv( str( self.ip_address ) ) is not None:
Jon Hallfc915882015-07-14 13:33:17 -070053 self.ip_address = os.getenv( str( self.ip_address ) )
54 else:
kelvin-onlab03eb88d2015-07-22 10:29:02 -070055 main.log.info( self.name + ": ip set to " + self.ip_address )
Jon Hallfc915882015-07-14 13:33:17 -070056 except KeyError:
Jon Hall3c0114c2020-08-11 15:07:42 -070057 main.log.info( self.name + ": Invalid host name," +
Jon Hallfc915882015-07-14 13:33:17 -070058 "defaulting to 'localhost' instead" )
59 self.ip_address = 'localhost'
60 except Exception as inst:
61 main.log.error( "Uncaught exception: " + str( inst ) )
62
Jon Hall6040bcf2017-08-14 11:15:41 -070063 return super( OnosRestDriver, self ).connect()
Jon Hallfc915882015-07-14 13:33:17 -070064
Jon Halle401b092015-09-23 13:34:24 -070065 def pprint( self, jsonObject ):
66 """
67 Pretty Prints a json object
68
69 arguments:
70 jsonObject - a parsed json object
71 returns:
72 A formatted string for printing or None on error
73 """
74 try:
Siddeshd9840842021-08-06 19:26:05 +000075 if not jsonObject:
76 return None
Jon Halle401b092015-09-23 13:34:24 -070077 if isinstance( jsonObject, str ):
78 jsonObject = json.loads( jsonObject )
79 return json.dumps( jsonObject, sort_keys=True,
Jeremy Ronquillo82705492017-10-18 14:19:55 -070080 indent=4, separators=( ',', ': ' ) )
Jon Halle401b092015-09-23 13:34:24 -070081 except ( TypeError, ValueError ):
Siddeshd9840842021-08-06 19:26:05 +000082 main.log.exception( "Error parsing jsonObject %s" % repr(jsonObject) )
Jon Halle401b092015-09-23 13:34:24 -070083 return None
84
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000085 def send( self, url, ip = "DEFAULT", port = "DEFAULT", base="/onos/v1", method="GET",
Jon Hallf7234882015-08-28 13:16:31 -070086 query=None, data=None, debug=False ):
Jon Hallfc915882015-07-14 13:33:17 -070087 """
88 Arguments:
89 str ip: ONOS IP Address
90 str port: ONOS REST Port
91 str url: ONOS REST url path.
92 NOTE that this is is only the relative path. IE "/devices"
93 str base: The base url for the given REST api. Applications could
94 potentially have their own base url
95 str method: HTTP method type
kelvin-onlab03eb88d2015-07-22 10:29:02 -070096 dict query: Dictionary to be sent in the query string for
Jon Hallfc915882015-07-14 13:33:17 -070097 the request
98 dict data: Dictionary to be sent in the body of the request
99 """
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000100 # TODO: Authentication - simple http (user,pass) tuple
Jon Hallfc915882015-07-14 13:33:17 -0700101 # TODO: should we maybe just pass kwargs straight to response?
102 # TODO: Do we need to allow for other protocols besides http?
103 # ANSWER: Not yet, but potentially https with certificates
suibin zhangd5b6fe42016-05-12 08:48:58 -0700104 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -0700105 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700106 ip = self.ip_address
suibin zhangd5b6fe42016-05-12 08:48:58 -0700107 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -0700108 main.log.warn( self.name + ": No port given, reverting to port " +
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700109 "from topo file" )
110 port = self.port
suibin zhang116647a2016-05-06 16:30:09 -0700111
Jon Hallfc915882015-07-14 13:33:17 -0700112 try:
113 path = "http://" + str( ip ) + ":" + str( port ) + base + url
Jon Hallf7234882015-08-28 13:16:31 -0700114 if self.user_name and self.pwd:
Jon Hall3c0114c2020-08-11 15:07:42 -0700115 main.log.info( self.name + ": user/passwd is: " + self.user_name + "/" + self.pwd )
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700116 auth = ( self.user_name, self.pwd )
Jon Hallf7234882015-08-28 13:16:31 -0700117 else:
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700118 auth = None
Jon Hall3c0114c2020-08-11 15:07:42 -0700119 main.log.info( self.name + ": Sending request " + path + " using " +
Jon Hallfc915882015-07-14 13:33:17 -0700120 method.upper() + " method." )
Jon Hallf69e3162020-09-01 09:08:44 -0700121 if debug:
122 main.log.debug( self.name + ": request data: " + str( data ) )
Jon Hall8e93b412021-08-10 14:42:42 -0700123 self.log( "Sending %s to %s with %s\n" % ( method.upper(),
124 path,
125 self.pprint( data ) ) )
Jon Hallfc915882015-07-14 13:33:17 -0700126 response = requests.request( method.upper(),
127 path,
128 params=query,
Jon Hallf7234882015-08-28 13:16:31 -0700129 data=data,
130 auth=auth )
Jon Hall8e93b412021-08-10 14:42:42 -0700131 self.log( "Received %s code with body: %s\n" % ( response.status_code,
132 self.pprint( response.text.encode( 'utf8' ) ) ) )
Jon Hallf7234882015-08-28 13:16:31 -0700133 if debug:
134 main.log.debug( response )
Jon Hallfc915882015-07-14 13:33:17 -0700135 return ( response.status_code, response.text.encode( 'utf8' ) )
You Wang7880b372019-02-27 16:50:47 -0800136 except requests.ConnectionError:
Jon Hallfc915882015-07-14 13:33:17 -0700137 main.log.exception( "Error sending request." )
You Wang7880b372019-02-27 16:50:47 -0800138 return ( None, None )
Jon Halle401b092015-09-23 13:34:24 -0700139 except Exception:
140 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700141 main.cleanAndExit()
Jon Hallfc915882015-07-14 13:33:17 -0700142
143 def intents( self, ip="DEFAULT", port="DEFAULT" ):
144 """
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700145 Description:
146 Gets a list of dictionary of all intents in the system
147 Returns:
148 A list of dictionary of intents in string type to match the cli
149 version for now; Returns main.FALSE if error on request;
150 Returns None for exception
Jon Hallfc915882015-07-14 13:33:17 -0700151 """
152 try:
153 output = None
154 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -0700155 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
Jon Hallfc915882015-07-14 13:33:17 -0700156 ip = self.ip_address
157 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -0700158 main.log.warn( self.name + ": No port given, reverting to port " +
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700159 "from topo file" )
Jon Hallfc915882015-07-14 13:33:17 -0700160 port = self.port
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000161 response = self.send( url="/intents", ip = ip, port = port )
Jon Hallfc915882015-07-14 13:33:17 -0700162 if response:
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700163 if 200 <= response[ 0 ] <= 299:
164 output = response[ 1 ]
165 a = json.loads( output ).get( 'intents' )
Jon Halle401b092015-09-23 13:34:24 -0700166 assert a is not None, "Error parsing json object"
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700167 b = json.dumps( a )
168 return b
Jon Hallfc915882015-07-14 13:33:17 -0700169 else:
Jon Hall3c0114c2020-08-11 15:07:42 -0700170 main.log.error( "Error with REST request, response was: %s: %s" %
171 ( response[ 0 ], response[ 1 ] ) )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700172 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700173 except ( AttributeError, AssertionError, TypeError ):
174 main.log.exception( self.name + ": Object not as expected" )
Jon Hallfc915882015-07-14 13:33:17 -0700175 return None
Jon Halle401b092015-09-23 13:34:24 -0700176 except Exception:
177 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700178 main.cleanAndExit()
Jon Hallfc915882015-07-14 13:33:17 -0700179
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700180 def intent( self, intentId, appId="org.onosproject.cli",
181 ip="DEFAULT", port="DEFAULT" ):
Jon Hallfc915882015-07-14 13:33:17 -0700182 """
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700183 Description:
184 Get the specific intent information of the given application ID and
185 intent ID
186 Required:
187 str intentId - Intent id in hexadecimal form
188 Optional:
189 str appId - application id of intent
190 Returns:
191 Returns an information dictionary of the given intent;
192 Returns main.FALSE if error on requests; Returns None for exception
193 NOTE:
194 The GET /intents REST api command accepts application id but the
195 api will get updated to accept application name instead
Jon Hallfc915882015-07-14 13:33:17 -0700196 """
197 try:
198 output = None
199 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -0700200 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
Jon Hallfc915882015-07-14 13:33:17 -0700201 ip = self.ip_address
202 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -0700203 main.log.warn( self.name + ": No port given, reverting to port " +
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700204 "from topo file" )
Jon Hallfc915882015-07-14 13:33:17 -0700205 port = self.port
206 # NOTE: REST url requires the intent id to be in decimal form
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700207 query = "/" + str( appId ) + "/" + str( intentId )
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000208 response = self.send( url="/intents" + query, ip = ip, port = port )
Jon Hallfc915882015-07-14 13:33:17 -0700209 if response:
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700210 if 200 <= response[ 0 ] <= 299:
211 output = response[ 1 ]
212 a = json.loads( output )
213 return a
Jon Hallfc915882015-07-14 13:33:17 -0700214 else:
Jon Hall3c0114c2020-08-11 15:07:42 -0700215 main.log.error( "Error with REST request, response was: %s: %s" %
216 ( response[ 0 ], response[ 1 ] ) )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700217 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700218 except ( AttributeError, TypeError ):
219 main.log.exception( self.name + ": Object not as expected" )
Jon Hallfc915882015-07-14 13:33:17 -0700220 return None
Jon Halle401b092015-09-23 13:34:24 -0700221 except Exception:
222 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700223 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700224
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700225 def apps( self, ip="DEFAULT", port="DEFAULT" ):
226 """
227 Description:
228 Returns all the current application installed in the system
229 Returns:
230 List of dictionary of installed application; Returns main.FALSE for
231 error on request; Returns None for exception
232 """
233 try:
234 output = None
235 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -0700236 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700237 ip = self.ip_address
238 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -0700239 main.log.warn( self.name + ": No port given, reverting to port " +
Jon Hallf7234882015-08-28 13:16:31 -0700240 "from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700241 port = self.port
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000242 response = self.send( url="/applications", ip = ip, port = port )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700243 if response:
244 if 200 <= response[ 0 ] <= 299:
245 output = response[ 1 ]
246 a = json.loads( output ).get( 'applications' )
Jon Halle401b092015-09-23 13:34:24 -0700247 assert a is not None, "Error parsing json object"
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700248 b = json.dumps( a )
249 return b
250 else:
Jon Hall3c0114c2020-08-11 15:07:42 -0700251 main.log.error( "Error with REST request, response was: %s: %s" %
252 ( response[ 0 ], response[ 1 ] ) )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700253 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700254 except ( AttributeError, AssertionError, TypeError ):
255 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700256 return None
Jon Halle401b092015-09-23 13:34:24 -0700257 except Exception:
258 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700259 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700260
261 def activateApp( self, appName, ip="DEFAULT", port="DEFAULT", check=True ):
262 """
263 Decription:
264 Activate an app that is already installed in ONOS
265 Optional:
266 bool check - If check is True, method will check the status
267 of the app after the command is issued
268 Returns:
269 Returns main.TRUE if the command was successfully or main.FALSE
270 if the REST responded with an error or given incorrect input;
271 Returns None for exception
272
273 """
274 try:
275 output = None
276 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -0700277 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700278 ip = self.ip_address
279 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -0700280 main.log.warn( self.name + ": No port given, reverting to port " +
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700281 "from topo file" )
282 port = self.port
283 query = "/" + str( appName ) + "/active"
Jon Hall3c0114c2020-08-11 15:07:42 -0700284 retry = 0
285 retCode = main.TRUE
286 while retry < 50:
287 if retry > 0:
288 main.log.warn( self.name + ": Retrying " + query + " for the " + str( retry ) + " time" )
289
290 retry += 1
291 response = self.send( method="POST",
292 debug=True,
293 url="/applications" + query,
294 ip = ip, port = port )
295 if response:
296 output = response[ 1 ]
297 if 200 <= response[ 0 ] <= 299:
298 if check:
299 app = json.loads( output )
300 if app.get( 'state' ) == 'ACTIVE':
301 main.log.info( self.name + ": " + appName +
302 " application" +
303 " is in ACTIVE state" )
304 appHealth = self.getAppHealth( appName=appName, ip=ip, port=port )
305 if "ready" == json.loads( appHealth[1] ).get( 'message' ):
306 return main.TRUE
307 else:
308 return main.FALSE
309 else:
310 main.log.error( self.name + ": " + appName +
311 " application" + " is in " +
312 app.get( 'state' ) + " state" )
313 retCode = main.FALSE
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700314 else:
Jon Hall3c0114c2020-08-11 15:07:42 -0700315 main.log.warn( self.name + ": Skipping " + appName +
316 "application check" )
317 return main.TRUE
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700318 else:
Jon Hall3c0114c2020-08-11 15:07:42 -0700319 main.log.error( "Error with REST request, response was: %s: %s" %
320 ( response[ 0 ], response[ 1 ] ) )
321 retCode = main.FALSE
322 time.sleep( 30 )
323 return retCode
324 except ( ValueError ):
325 main.log.exception( self.name + ": Error parsing json" )
326 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700327 except ( AttributeError, TypeError ):
328 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700329 return None
Jon Halle401b092015-09-23 13:34:24 -0700330 except Exception:
331 main.log.exception( self.name + ": Uncaught exception!" )
Jon Hall3c0114c2020-08-11 15:07:42 -0700332 main.log.debug( self.name + ": " + response )
Devin Lim44075962017-08-11 10:56:37 -0700333 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700334
335 def deactivateApp( self, appName, ip="DEFAULT", port="DEFAULT",
336 check=True ):
337 """
338 Required:
339 Deactivate an app that is already activated in ONOS
340 Optional:
341 bool check - If check is True, method will check the status of the
342 app after the command is issued
343 Returns:
344 Returns main.TRUE if the command was successfully sent
345 main.FALSE if the REST responded with an error or given
346 incorrect input; Returns None for exception
347 """
348 try:
349 output = None
350 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -0700351 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700352 ip = self.ip_address
353 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -0700354 main.log.warn( self.name + ": No port given, reverting to port " +
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700355 "from topo file" )
356 port = self.port
357 query = "/" + str( appName ) + "/active"
Devin Limcde503f2017-09-11 17:23:30 -0700358 self.send( method="DELETE",
359 url="/applications" + query,
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000360 ip = ip, port = port )
Devin Limcde503f2017-09-11 17:23:30 -0700361 response = self.getApp( appName, ip, port )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700362 if response:
363 output = response[ 1 ]
Jon Hall6040bcf2017-08-14 11:15:41 -0700364 app = {} if output == "" else json.loads( output )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700365 if 200 <= response[ 0 ] <= 299:
366 if check:
367 if app.get( 'state' ) == 'INSTALLED':
368 main.log.info( self.name + ": " + appName +
369 " application" +
370 " is in INSTALLED state" )
371 return main.TRUE
372 else:
373 main.log.error( self.name + ": " + appName +
374 " application" + " is in " +
375 app.get( 'state' ) + " state" )
376 return main.FALSE
377 else:
Jon Hall3c0114c2020-08-11 15:07:42 -0700378 main.log.warn( self.name + ": Skipping " + appName +
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700379 "application check" )
380 return main.TRUE
381 else:
Jon Hall3c0114c2020-08-11 15:07:42 -0700382 main.log.error( "Error with REST request, response was: %s: %s" %
383 ( response[ 0 ], response[ 1 ] ) )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700384 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700385 except ( AttributeError, TypeError ):
386 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700387 return None
Jon Halle401b092015-09-23 13:34:24 -0700388 except Exception:
389 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700390 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700391
Devin Limcde503f2017-09-11 17:23:30 -0700392 def getApp( self, appName, ip="DEFAULT",
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700393 port="DEFAULT" ):
394 """
395 Decription:
396 Gets the informaion of the given application
397 Required:
398 str name - Name of onos application
399 Returns:
400 Returns a dictionary of information ONOS application in string type;
401 Returns main.FALSE if error on requests; Returns None for exception
402 """
403 try:
Jon Hall3c0114c2020-08-11 15:07:42 -0700404 response = None
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700405 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -0700406 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700407 ip = self.ip_address
408 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -0700409 main.log.warn( self.name + ": No port given, reverting to port " +
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700410 "from topo file" )
411 port = self.port
Devin Limcde503f2017-09-11 17:23:30 -0700412 query = "/" + str( appName )
suibin zhangd5b6fe42016-05-12 08:48:58 -0700413 response = self.send( url="/applications" + query,
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000414 ip = ip, port = port )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700415 if response:
416 if 200 <= response[ 0 ] <= 299:
Devin Limcde503f2017-09-11 17:23:30 -0700417 return response
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700418 else:
Jon Hall3c0114c2020-08-11 15:07:42 -0700419 main.log.error( "Error with REST request, response was: %s: %s" %
420 ( response[ 0 ], response[ 1 ] ) )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700421 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700422 except ( AttributeError, TypeError ):
423 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700424 return None
Jon Halle401b092015-09-23 13:34:24 -0700425 except Exception:
426 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700427 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700428
Jon Hall3c0114c2020-08-11 15:07:42 -0700429 def getAppHealth( self, appName, ip="DEFAULT",
430 port="DEFAULT" ):
431 """
432 Decription:
433 Gets the health of the given application
434 Required:
435 str name - Name of onos application
436 Returns:
437 Returns a dictionary of information ONOS application in string type;
438 Returns main.FALSE if error on requests; Returns None for exception
439 """
440 try:
441 response = None
442 if ip == "DEFAULT":
443 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
444 ip = self.ip_address
445 if port == "DEFAULT":
446 main.log.warn( self.name + ": No port given, reverting to port " +
447 "from topo file" )
448 port = self.port
449 response = self.send( url="/applications/%s/health" % str( appName ),
450 ip = ip, port = port )
451 if response:
452 if 200 <= response[ 0 ] <= 299:
453 return response
454 else:
455 main.log.error( "Error with REST request, response was: %s: %s" %
456 ( response[ 0 ], response[ 1 ] ) )
457 return main.FALSE
458 except ( AttributeError, TypeError ):
459 main.log.exception( self.name + ": Object not as expected" )
460 return None
461 except Exception:
462 main.log.exception( self.name + ": Uncaught exception!" )
463 main.cleanAndExit()
464
465 def getAllAppHealth( self, retries=1, wait=30 , ip="DEFAULT",
466 port="DEFAULT" ):
467 """
468 Description:
469 Gets the health of all activated apps
470 Required:
471 Optional:
472 retries - The number of tries to return before returning
473 wait - Time to wait in between retries
474 """
475 try:
476 responses = main.TRUE
477 if ip == "DEFAULT":
478 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
479 ip = self.ip_address
480 if port == "DEFAULT":
481 main.log.warn( self.name + ": No port given, reverting to port " +
482 "from topo file" )
483 port = self.port
484 apps = self.apps()
485 for app in json.loads(apps):
486 appName = app.get( "name" )
487 response = self.getAppHealth( appName=appName, ip=ip, port=port )
488 responses = main.TRUE and "ready" == json.loads( response[1] ).get( "message" )
489 return responses
490 except ( AttributeError, TypeError ):
491 main.log.exception( self.name + ": Object not as expected" )
492 return None
493 except Exception:
494 main.log.exception( self.name + ": Uncaught exception!" )
495 main.cleanAndExit()
496
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700497 def addHostIntent( self, hostIdOne, hostIdTwo, appId='org.onosproject.cli',
Jeremy Songsterae2dd452016-05-17 16:44:35 -0700498 ip="DEFAULT", port="DEFAULT", vlanId="" ):
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700499 """
500 Description:
501 Adds a host-to-host intent ( bidirectional ) by
502 specifying the two hosts.
503 Required:
504 * hostIdOne: ONOS host id for host1
505 * hostIdTwo: ONOS host id for host2
506 Optional:
507 str appId - Application name of intent identifier
508 Returns:
kelvin-onlabb50074f2015-07-27 16:18:32 -0700509 Returns main.TRUE for successful requests; Returns main.FALSE if
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700510 error on requests; Returns None for exceptions
511 """
512 try:
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700513 intentJson = { "two": str( hostIdTwo ),
514 "selector": { "criteria": [] }, "priority": 7,
515 "treatment": { "deferred": [], "instructions": [] },
516 "appId": appId, "one": str( hostIdOne ),
517 "type": "HostToHostIntent",
518 "constraints": [ { "type": "LinkTypeConstraint",
519 "types": [ "OPTICAL" ],
520 "inclusive": 'false' } ] }
Jeremy Songsterae2dd452016-05-17 16:44:35 -0700521 if vlanId:
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700522 intentJson[ 'selector' ][ 'criteria' ].append( { "type": "VLAN_VID",
523 "vlanId": vlanId } )
Jon Hall3c0114c2020-08-11 15:07:42 -0700524 response = None
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700525 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -0700526 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700527 ip = self.ip_address
528 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -0700529 main.log.warn( self.name + ": No port given, reverting to port " +
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700530 "from topo file" )
531 port = self.port
suibin zhang116647a2016-05-06 16:30:09 -0700532 response = self.send( method="POST",
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000533 url="/intents", ip = ip, port = port,
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700534 data=json.dumps( intentJson ) )
535 if response:
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700536 if "201" in str( response[ 0 ] ):
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700537 main.log.info( self.name + ": Successfully POST host" +
538 " intent between host: " + hostIdOne +
539 " and host: " + hostIdTwo )
540 return main.TRUE
541 else:
Jon Hall3c0114c2020-08-11 15:07:42 -0700542 main.log.error( "Error with REST request, response was: %s: %s" %
543 ( response[ 0 ], response[ 1 ] ) )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700544 return main.FALSE
545
Jon Halle401b092015-09-23 13:34:24 -0700546 except ( AttributeError, TypeError ):
547 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700548 return None
Jon Halle401b092015-09-23 13:34:24 -0700549 except Exception:
550 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700551 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700552
kelvin-onlabb50074f2015-07-27 16:18:32 -0700553 def addPointIntent( self,
554 ingressDevice,
555 egressDevice,
kelvin-onlabb50074f2015-07-27 16:18:32 -0700556 appId='org.onosproject.cli',
557 ingressPort="",
558 egressPort="",
559 ethType="",
560 ethSrc="",
561 ethDst="",
562 bandwidth="",
alisonda157272016-12-22 01:13:21 -0800563 protected=False,
kelvin-onlabb50074f2015-07-27 16:18:32 -0700564 lambdaAlloc=False,
565 ipProto="",
566 ipSrc="",
567 ipDst="",
568 tcpSrc="",
kelvin-onlab9b42b0a2015-08-05 14:43:58 -0700569 tcpDst="",
570 ip="DEFAULT",
Jeremy Songsterae2dd452016-05-17 16:44:35 -0700571 port="DEFAULT",
572 vlanId="" ):
kelvin-onlabb50074f2015-07-27 16:18:32 -0700573 """
574 Description:
575 Adds a point-to-point intent ( uni-directional ) by
576 specifying device id's and optional fields
577 Required:
578 * ingressDevice: device id of ingress device
579 * egressDevice: device id of egress device
580 Optional:
581 * ethType: specify ethType
582 * ethSrc: specify ethSrc ( i.e. src mac addr )
583 * ethDst: specify ethDst ( i.e. dst mac addr )
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000584 * bandwidth: specify bandwidth capacity of link (TODO)
kelvin-onlabb50074f2015-07-27 16:18:32 -0700585 * lambdaAlloc: if True, intent will allocate lambda
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000586 for the specified intent (TODO)
kelvin-onlabb50074f2015-07-27 16:18:32 -0700587 * ipProto: specify ip protocol
588 * ipSrc: specify ip source address with mask eg. ip#/24
589 * ipDst: specify ip destination address eg. ip#/24
590 * tcpSrc: specify tcp source port
591 * tcpDst: specify tcp destination port
592 Returns:
593 Returns main.TRUE for successful requests; Returns main.FALSE if
594 no ingress|egress port found and if error on requests;
595 Returns None for exceptions
596 NOTE:
597 The ip and port option are for the requests input's ip and port
598 of the ONOS node
599 """
600 try:
601 if "/" in ingressDevice:
602 if not ingressPort:
603 ingressPort = ingressDevice.split( "/" )[ 1 ]
604 ingressDevice = ingressDevice.split( "/" )[ 0 ]
605 else:
606 if not ingressPort:
607 main.log.debug( self.name + ": Ingress port not specified" )
608 return main.FALSE
609
610 if "/" in egressDevice:
611 if not egressPort:
612 egressPort = egressDevice.split( "/" )[ 1 ]
613 egressDevice = egressDevice.split( "/" )[ 0 ]
614 else:
615 if not egressPort:
616 main.log.debug( self.name + ": Egress port not specified" )
617 return main.FALSE
618
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700619 intentJson = { "ingressPoint": { "device": ingressDevice,
620 "port": ingressPort },
621 "selector": { "criteria": [] },
622 "priority": 55,
623 "treatment": { "deferred": [],
624 "instructions": [] },
625 "egressPoint": { "device": egressDevice,
626 "port": egressPort },
627 "appId": appId,
628 "type": "PointToPointIntent",
629 "constraints": [ { "type": "LinkTypeConstraint",
630 "types": [ "OPTICAL" ],
631 "inclusive": "false" } ] }
kelvin-onlabb50074f2015-07-27 16:18:32 -0700632
633 if ethType == "IPV4":
634 intentJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700635 "type": "ETH_TYPE",
636 "ethType": 2048 } )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -0700637 elif ethType:
638 intentJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700639 "type": "ETH_TYPE",
640 "ethType": ethType } )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -0700641
kelvin-onlabb50074f2015-07-27 16:18:32 -0700642 if ethSrc:
643 intentJson[ 'selector' ][ 'criteria' ].append(
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700644 { "type": "ETH_SRC",
645 "mac": ethSrc } )
kelvin-onlabb50074f2015-07-27 16:18:32 -0700646 if ethDst:
647 intentJson[ 'selector' ][ 'criteria' ].append(
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700648 { "type": "ETH_DST",
649 "mac": ethDst } )
kelvin-onlabb50074f2015-07-27 16:18:32 -0700650 if ipSrc:
651 intentJson[ 'selector' ][ 'criteria' ].append(
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700652 { "type": "IPV4_SRC",
653 "ip": ipSrc } )
kelvin-onlabb50074f2015-07-27 16:18:32 -0700654 if ipDst:
655 intentJson[ 'selector' ][ 'criteria' ].append(
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700656 { "type": "IPV4_DST",
657 "ip": ipDst } )
kelvin-onlabb50074f2015-07-27 16:18:32 -0700658 if tcpSrc:
659 intentJson[ 'selector' ][ 'criteria' ].append(
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700660 { "type": "TCP_SRC",
kelvin-onlabb50074f2015-07-27 16:18:32 -0700661 "tcpPort": tcpSrc } )
662 if tcpDst:
663 intentJson[ 'selector' ][ 'criteria' ].append(
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700664 { "type": "TCP_DST",
kelvin-onlabb50074f2015-07-27 16:18:32 -0700665 "tcpPort": tcpDst } )
666 if ipProto:
667 intentJson[ 'selector' ][ 'criteria' ].append(
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700668 { "type": "IP_PROTO",
kelvin-onlabb50074f2015-07-27 16:18:32 -0700669 "protocol": ipProto } )
Jeremy Songsterae2dd452016-05-17 16:44:35 -0700670 if vlanId:
671 intentJson[ 'selector' ][ 'criteria' ].append(
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700672 { "type": "VLAN_VID",
Jeremy Songsterae2dd452016-05-17 16:44:35 -0700673 "vlanId": vlanId } )
kelvin-onlabb50074f2015-07-27 16:18:32 -0700674
675 # TODO: Bandwidth and Lambda will be implemented if needed
676
Jon Hall3c0114c2020-08-11 15:07:42 -0700677 response = None
kelvin-onlabb50074f2015-07-27 16:18:32 -0700678 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -0700679 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
kelvin-onlabb50074f2015-07-27 16:18:32 -0700680 ip = self.ip_address
681 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -0700682 main.log.warn( self.name + ": No port given, reverting to port " +
kelvin-onlabb50074f2015-07-27 16:18:32 -0700683 "from topo file" )
684 port = self.port
suibin zhang116647a2016-05-06 16:30:09 -0700685 response = self.send( method="POST",
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000686 url="/intents", ip = ip, port = port,
kelvin-onlabb50074f2015-07-27 16:18:32 -0700687 data=json.dumps( intentJson ) )
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700688
689 main.log.debug( intentJson )
690
kelvin-onlabb50074f2015-07-27 16:18:32 -0700691 if response:
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700692 if "201" in str( response[ 0 ] ):
kelvin-onlabb50074f2015-07-27 16:18:32 -0700693 main.log.info( self.name + ": Successfully POST point" +
694 " intent between ingress: " + ingressDevice +
695 " and egress: " + egressDevice + " devices" )
696 return main.TRUE
697 else:
Jon Hall3c0114c2020-08-11 15:07:42 -0700698 main.log.error( "Error with REST request, response was: %s: %s" %
699 ( response[ 0 ], response[ 1 ] ) )
kelvin-onlabb50074f2015-07-27 16:18:32 -0700700 return main.FALSE
701
Jon Halle401b092015-09-23 13:34:24 -0700702 except ( AttributeError, TypeError ):
703 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlabb50074f2015-07-27 16:18:32 -0700704 return None
Jon Halle401b092015-09-23 13:34:24 -0700705 except Exception:
706 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700707 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700708
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700709 def addSinglepointToMultipointIntent( self,
710 ingressDevice,
711 egressDeviceList,
712 portEgressList,
713 appId='org.onosproject.cli',
714 portIngress="",
715 ethType="",
716 ethSrc="",
717 ethDst="",
718 bandwidth="",
719 lambdaAlloc=False,
720 ipProto="",
721 ipSrc="",
722 ipDst="",
723 tcpSrc="",
724 tcpDst="",
725 partial=False,
726 ip="DEFAULT",
727 port="DEFAULT",
728 vlanId="" ):
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700729 """
730 Description:
731 Adds a point-to-multi point intent ( uni-directional ) by
732 specifying device id's and optional fields
733 Required:
734 * ingressDevice: device id of ingress device
735 * egressDevice: device id of egress device
736 * portEgressList: a list of port id of egress device
737
738 Optional:
739 * portIngress: port id of ingress device
740 * ethType: specify ethType
741 * ethSrc: specify ethSrc ( i.e. src mac addr )
742 * ethDst: specify ethDst ( i.e. dst mac addr )
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000743 * bandwidth: specify bandwidth capacity of link (TODO)
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700744 * lambdaAlloc: if True, intent will allocate lambda
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000745 for the specified intent (TODO)
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700746 * ipProto: specify ip protocol
747 * ipSrc: specify ip source address with mask eg. ip#/24
748 * ipDst: specify ip destination address eg. ip#/24
749 * tcpSrc: specify tcp source port
750 * tcpDst: specify tcp destination port
751 Returns:
752 Returns main.TRUE for successful requests; Returns main.FALSE if
753 no ingress|egress port found and if error on requests;
754 Returns None for exceptions
755 NOTE:
756 The ip and port option are for the requests input's ip and port
757 of the ONOS node
758 """
759 try:
760
761 if "/" in ingressDevice:
762 if not portIngress:
763 ingressPort = ingressDevice.split( "/" )[ 1 ]
764 ingressDevice = ingressDevice.split( "/" )[ 0 ]
765 else:
766 if not portIngress:
767 main.log.debug( self.name + ": Ingress port not specified" )
768 return main.FALSE
769 index = 0
770 for egressDevice in egressDeviceList:
771 if "/" in egressDevice:
772 portEgressList.append( egressDevice.split( "/" )[ 1 ] )
773 egressDeviceList[ index ] = egressDevice.split( "/" )[ 0 ]
774 else:
775 if not portEgressList:
776 main.log.debug( self.name + ": Egress port not specified" )
777 return main.FALSE
778 index = index + 1
779
780 intentJson = { "ingressPoint": { "device": ingressDevice,
781 "port": ingressPort },
782 "selector": { "criteria": [] },
783 "priority": 55,
784 "treatment": { "deferred": [],
785 "instructions": [] },
786 "egressPoint": { "connectPoints": [] },
787 "appId": appId,
788 "type": "SinglePointToMultiPointIntent",
789 "constraints": [ { "type": "LinkTypeConstraint",
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700790 "types": [ "OPTICAL" ],
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700791 "inclusive": "false" } ] }
792
793 index = 0
794 for ep in portEgressList:
795 intentJson[ 'egressPoint' ][ 'connectPoints' ].append(
796 { "device": egressDeviceList[ index ],
797 "port": ep } )
798 index += 1
799
800 if ethType == "IPV4":
801 intentJson[ 'selector' ][ 'criteria' ].append(
802 { "type": "ETH_TYPE",
803 "ethType": 2048 } )
804 elif ethType:
805 intentJson[ 'selector' ][ 'criteria' ].append(
806 { "type": "ETH_TYPE",
807 "ethType": ethType } )
808
809 if ethSrc:
810 intentJson[ 'selector' ][ 'criteria' ].append(
811 { "type": "ETH_SRC",
812 "mac": ethSrc } )
813
814 if ethDst:
815 for dst in ethDst:
816 if dst:
817 intentJson[ 'selector' ][ 'criteria' ].append(
818 { "type": "ETH_DST",
819 "mac": dst } )
820 if tcpSrc:
821 intentJson[ 'selector' ][ 'criteria' ].append(
822 { "type": "TCP_SRC",
823 "tcpPort": tcpSrc } )
824 if tcpDst:
825 intentJson[ 'selector' ][ 'criteria' ].append(
826 { "type": "TCP_DST",
827 "tcpPort": tcpDst } )
828 if ipProto:
829 intentJson[ 'selector' ][ 'criteria' ].append(
830 { "type": "IP_PROTO",
831 "protocol": ipProto } )
832 if vlanId:
833 intentJson[ 'selector' ][ 'criteria' ].append(
834 { "type": "VLAN_VID",
835 "vlanId": vlanId } )
836
837 # TODO: Bandwidth and Lambda will be implemented if needed
838
Jon Hall3c0114c2020-08-11 15:07:42 -0700839 response = None
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700840 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -0700841 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700842 ip = self.ip_address
843 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -0700844 main.log.warn( self.name + ": No port given, reverting to port " +
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700845 "from topo file" )
846 port = self.port
847 response = self.send( method="POST",
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700848 url="/intents", ip=ip, port=port,
849 data=json.dumps( intentJson ) )
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700850
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700851 main.log.debug( intentJson )
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700852
853 if response:
854 if "201" in str( response[ 0 ] ):
855 main.log.info( self.name + ": Successfully POST point" +
856 " intent between ingress: " + ingressDevice +
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700857 " and egress: " + str( egressDeviceList ) + " devices" )
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700858 return main.TRUE
859 else:
Jon Hall3c0114c2020-08-11 15:07:42 -0700860 main.log.error( "Error with REST request, response was: %s: %s" % ( response[ 0 ], response[ 1 ] ) )
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700861 return main.FALSE
862 else:
863 main.log.error( "REST request has no response." )
864 return main.FALSE
865
866 except ( AttributeError, TypeError ):
867 main.log.exception( self.name + ": Object not as expected" )
868 return None
869 except Exception:
870 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700871 main.cleanAndExit()
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700872
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700873 def removeIntent( self, intentId, appId='org.onosproject.cli',
874 ip="DEFAULT", port="DEFAULT" ):
875 """
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700876 Remove intent for specified application id and intent id;
877 Returns None for exception
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700878 """
879 try:
Jon Hall3c0114c2020-08-11 15:07:42 -0700880 response = None
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700881 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -0700882 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700883 ip = self.ip_address
884 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -0700885 main.log.warn( self.name + ": No port given, reverting to port " +
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700886 "from topo file" )
887 port = self.port
888 # NOTE: REST url requires the intent id to be in decimal form
889 query = "/" + str( appId ) + "/" + str( int( intentId, 16 ) )
suibin zhang116647a2016-05-06 16:30:09 -0700890 response = self.send( method="DELETE",
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000891 url="/intents" + query, ip = ip, port = port )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700892 if response:
893 if 200 <= response[ 0 ] <= 299:
894 return main.TRUE
895 else:
Jon Hall3c0114c2020-08-11 15:07:42 -0700896 main.log.error( "Error with REST request, response was: %s: %s" %
897 ( response[ 0 ], response[ 1 ] ) )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700898 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700899 except ( AttributeError, TypeError ):
900 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700901 return None
Jon Halle401b092015-09-23 13:34:24 -0700902 except Exception:
903 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700904 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700905
Jon Hall3c0114c2020-08-11 15:07:42 -0700906 def getIntentsId( self, ip="DEFAULT", port="DEFAULT" ):
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700907 """
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700908 Description:
909 Gets all intents ID using intents function
910 Returns:
911 List of intents ID if found any intents; Returns main.FALSE for other exceptions
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700912 """
913 try:
914 intentIdList = []
Jon Hall3c0114c2020-08-11 15:07:42 -0700915 intentsJson = json.loads( self.intents( ip=ip, port=port ) )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700916 for intent in intentsJson:
917 intentIdList.append( intent.get( 'id' ) )
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700918 if not intentIdList:
Jon Hall3c0114c2020-08-11 15:07:42 -0700919 main.log.debug( self.name + ": Cannot find any intents" )
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700920 return main.FALSE
921 else:
922 return intentIdList
Jon Halle401b092015-09-23 13:34:24 -0700923 except ( AttributeError, TypeError ):
924 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700925 return None
Jon Halle401b092015-09-23 13:34:24 -0700926 except Exception:
927 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700928 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700929
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700930 def removeAllIntents( self, intentIdList ='ALL', appId='org.onosproject.cli',
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700931 ip="DEFAULT", port="DEFAULT", delay=5 ):
932 """
933 Description:
934 Remove all the intents
935 Returns:
936 Returns main.TRUE if all intents are removed, otherwise returns
937 main.FALSE; Returns None for exception
938 """
939 try:
940 results = []
941 if intentIdList == 'ALL':
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700942 # intentIdList = self.getIntentsId( ip=ip, port=port )
943 intentIdList = self.getIntentsId()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700944
945 main.log.info( self.name + ": Removing intents " +
946 str( intentIdList ) )
947
948 if isinstance( intentIdList, types.ListType ):
949 for intent in intentIdList:
950 results.append( self.removeIntent( intentId=intent,
951 appId=appId,
952 ip=ip,
953 port=port ) )
954 # Check for remaining intents
955 # NOTE: Noticing some delay on Deleting the intents so i put
956 # this time out
957 import time
958 time.sleep( delay )
959 intentRemain = len( json.loads( self.intents() ) )
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700960 if all( result == main.TRUE for result in results ) and \
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700961 intentRemain == 0:
962 main.log.info( self.name + ": All intents are removed " )
963 return main.TRUE
964 else:
965 main.log.error( self.name + ": Did not removed all intents,"
966 + " there are " + str( intentRemain )
967 + " intents remaining" )
968 return main.FALSE
969 else:
970 main.log.debug( self.name + ": There is no intents ID list" )
Jon Halle401b092015-09-23 13:34:24 -0700971 except ( AttributeError, TypeError ):
972 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700973 return None
Jon Halle401b092015-09-23 13:34:24 -0700974 except Exception:
975 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700976 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700977
978 def hosts( self, ip="DEFAULT", port="DEFAULT" ):
979 """
980 Description:
981 Get a list of dictionary of all discovered hosts
982 Returns:
983 Returns a list of dictionary of information of the hosts currently
984 discovered by ONOS; Returns main.FALSE if error on requests;
985 Returns None for exception
986 """
987 try:
988 output = None
989 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -0700990 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700991 ip = self.ip_address
992 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -0700993 main.log.warn( self.name + ": No port given, reverting to port " +
Jon Hallf7234882015-08-28 13:16:31 -0700994 "from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700995 port = self.port
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000996 response = self.send( url="/hosts", ip = ip, port = port )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700997 if response:
998 if 200 <= response[ 0 ] <= 299:
999 output = response[ 1 ]
1000 a = json.loads( output ).get( 'hosts' )
Jon Halle401b092015-09-23 13:34:24 -07001001 assert a is not None, "Error parsing json object"
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001002 b = json.dumps( a )
1003 return b
1004 else:
Jon Hall3c0114c2020-08-11 15:07:42 -07001005 main.log.error( "Error with REST request, response was: %s: %s" %
1006 ( response[ 0 ], response[ 1 ] ) )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001007 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -07001008 except ( AttributeError, AssertionError, TypeError ):
1009 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001010 return None
Jon Halle401b092015-09-23 13:34:24 -07001011 except Exception:
1012 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001013 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001014
1015 def getHost( self, mac, vlan="-1", ip="DEFAULT", port="DEFAULT" ):
1016 """
1017 Description:
1018 Gets the information from the given host
1019 Required:
1020 str mac - MAC address of the host
1021 Optional:
1022 str vlan - VLAN tag of the host, defaults to -1
1023 Returns:
1024 Return the host id from the hosts/mac/vlan output in REST api
1025 whose 'id' contains mac/vlan; Returns None for exception;
1026 Returns main.FALSE if error on requests
1027
1028 NOTE:
1029 Not sure what this function should do, any suggestion?
1030 """
1031 try:
1032 output = None
1033 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07001034 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001035 ip = self.ip_address
1036 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07001037 main.log.warn( self.name + ": No port given, reverting to port " +
Jon Hallf7234882015-08-28 13:16:31 -07001038 "from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001039 port = self.port
1040 query = "/" + mac + "/" + vlan
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001041 response = self.send( url="/hosts" + query, ip = ip, port = port )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001042 if response:
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001043 # NOTE: What if the person wants other values? would it be better
1044 # to have a function that gets a key and return a value instead?
1045 # This function requires mac and vlan and returns an ID which
1046 # makes this current function useless
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001047 if 200 <= response[ 0 ] <= 299:
1048 output = response[ 1 ]
1049 hostId = json.loads( output ).get( 'id' )
1050 return hostId
1051 else:
Jon Hall3c0114c2020-08-11 15:07:42 -07001052 main.log.error( "Error with REST request, response was: %s: %s" %
1053 ( response[ 0 ], response[ 1 ] ) )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001054 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -07001055 except ( AttributeError, TypeError ):
1056 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001057 return None
Jon Halle401b092015-09-23 13:34:24 -07001058 except Exception:
1059 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001060 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001061
1062 def topology( self, ip="DEFAULT", port="DEFAULT" ):
1063 """
1064 Description:
1065 Gets the overview of network topology
1066 Returns:
1067 Returns a dictionary containing information about network topology;
1068 Returns None for exception
1069 """
1070 try:
1071 output = None
1072 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07001073 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001074 ip = self.ip_address
1075 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07001076 main.log.warn( self.name + ": No port given, reverting to port " +
Jon Hallf7234882015-08-28 13:16:31 -07001077 "from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001078 port = self.port
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001079 response = self.send( url="/topology", ip = ip, port = port )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001080 if response:
1081 if 200 <= response[ 0 ] <= 299:
1082 output = response[ 1 ]
1083 a = json.loads( output )
1084 b = json.dumps( a )
1085 return b
1086 else:
Jon Hall3c0114c2020-08-11 15:07:42 -07001087 main.log.error( "Error with REST request, response was: %s: %s" %
1088 ( response[ 0 ], response[ 1 ] ) )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001089 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -07001090 except ( AttributeError, TypeError ):
1091 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001092 return None
Jon Halle401b092015-09-23 13:34:24 -07001093 except Exception:
1094 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001095 main.cleanAndExit()
Jon Halle401b092015-09-23 13:34:24 -07001096
1097 def devices( self, ip="DEFAULT", port="DEFAULT" ):
1098 """
1099 Description:
1100 Get the devices discovered by ONOS is json string format
1101 Returns:
1102 a json string of the devices currently discovered by ONOS OR
1103 main.FALSE if there is an error in the request OR
1104 Returns None for exception
1105 """
1106 try:
1107 output = None
1108 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07001109 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
Jon Halle401b092015-09-23 13:34:24 -07001110 ip = self.ip_address
1111 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07001112 main.log.warn( self.name + ": No port given, reverting to port " +
Jon Halle401b092015-09-23 13:34:24 -07001113 "from topo file" )
1114 port = self.port
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001115 response = self.send( url="/devices", ip = ip, port = port )
Jon Halle401b092015-09-23 13:34:24 -07001116 if response:
1117 if 200 <= response[ 0 ] <= 299:
1118 output = response[ 1 ]
1119 a = json.loads( output ).get( 'devices' )
1120 assert a is not None, "Error parsing json object"
1121 b = json.dumps( a )
1122 return b
1123 else:
Jon Hall3c0114c2020-08-11 15:07:42 -07001124 main.log.error( "Error with REST request, response was: %s: %s" %
1125 ( response[ 0 ], response[ 1 ] ) )
Jon Halle401b092015-09-23 13:34:24 -07001126 return main.FALSE
1127 except ( AttributeError, AssertionError, TypeError ):
1128 main.log.exception( self.name + ": Object not as expected" )
1129 return None
1130 except Exception:
1131 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001132 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001133
1134 def getIntentState( self, intentsId, intentsJson=None,
1135 ip="DEFAULT", port="DEFAULT" ):
1136 """
1137 Description:
1138 Get intent state.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001139 Accepts a single intent ID (string type) or a list of intent IDs.
1140 Returns the state(string type) of the id if a single intent ID is
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001141 accepted.
1142 Required:
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001143 intentId: intent ID (string type)
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001144 intentsJson: parsed json object from the onos:intents api
1145 Returns:
1146 Returns a dictionary with intent IDs as the key and its
1147 corresponding states as the values; Returns None for invalid IDs or
1148 Type error and any exceptions
1149 NOTE:
1150 An intent's state consist of INSTALLED,WITHDRAWN etc.
1151 """
1152 try:
1153 state = "State is Undefined"
1154 if not intentsJson:
1155 intentsJsonTemp = json.loads( self.intents() )
1156 else:
1157 intentsJsonTemp = json.loads( intentsJson )
1158 if isinstance( intentsId, types.StringType ):
1159 for intent in intentsJsonTemp:
1160 if intentsId == intent[ 'id' ]:
1161 state = intent[ 'state' ]
1162 return state
Jon Hall3c0114c2020-08-11 15:07:42 -07001163 main.log.info( self.name + ": Cannot find intent ID" + str( intentsId ) +
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001164 " on the list" )
1165 return state
1166 elif isinstance( intentsId, types.ListType ):
1167 dictList = []
1168 for i in xrange( len( intentsId ) ):
1169 stateDict = {}
1170 for intents in intentsJsonTemp:
1171 if intentsId[ i ] == intents[ 'id' ]:
1172 stateDict[ 'state' ] = intents[ 'state' ]
1173 stateDict[ 'id' ] = intentsId[ i ]
1174 dictList.append( stateDict )
1175 break
1176 if len( intentsId ) != len( dictList ):
Jon Hall3c0114c2020-08-11 15:07:42 -07001177 main.log.info( self.name + ": Cannot find some of the intent ID state" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001178 return dictList
1179 else:
Jon Hall3c0114c2020-08-11 15:07:42 -07001180 main.log.info( self.name + ": Invalid intents ID entry" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001181 return None
1182
Jon Halle401b092015-09-23 13:34:24 -07001183 except ( AttributeError, TypeError ):
1184 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001185 return None
Jon Halle401b092015-09-23 13:34:24 -07001186 except Exception:
1187 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001188 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001189
1190 def checkIntentState( self, intentsId="ALL", expectedState='INSTALLED',
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001191 ip="DEFAULT", port="DEFAULT" ):
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001192 """
1193 Description:
1194 Check intents state based on expected state which defaults to
1195 INSTALLED state
1196 Required:
1197 intentsId - List of intents ID to be checked
1198 Optional:
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001199 expectedState - Check the expected state(s) of each intents
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001200 state in the list.
1201 *NOTE: You can pass in a list of expected state,
1202 Eg: expectedState = [ 'INSTALLED' , 'INSTALLING' ]
1203 Return:
1204 Returns main.TRUE only if all intent are the same as expected states
1205 , otherwise, returns main.FALSE; Returns None for general exception
1206 """
1207 try:
1208 # Generating a dictionary: intent id as a key and state as value
1209 returnValue = main.TRUE
1210 if intentsId == "ALL":
1211 intentsId = self.getIntentsId( ip=ip, port=port )
1212 intentsDict = self.getIntentState( intentsId, ip=ip, port=port )
1213
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001214 if len( intentsId ) != len( intentsDict ):
1215 main.log.error( self.name + ": There is something wrong " +
1216 "getting intents state" )
1217 return main.FALSE
1218
1219 if isinstance( expectedState, types.StringType ):
1220 for intents in intentsDict:
1221 if intents.get( 'state' ) != expectedState:
Jon Hall3c0114c2020-08-11 15:07:42 -07001222 main.log.debug( self.name + ": Intent ID - " +
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001223 intents.get( 'id' ) +
1224 " actual state = " +
1225 intents.get( 'state' )
1226 + " does not equal expected state = "
1227 + expectedState )
1228 returnValue = main.FALSE
1229
1230 elif isinstance( expectedState, types.ListType ):
1231 for intents in intentsDict:
1232 if not any( state == intents.get( 'state' ) for state in
1233 expectedState ):
Jon Hall3c0114c2020-08-11 15:07:42 -07001234 main.log.debug( self.name + ": Intent ID - " +
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001235 intents.get( 'id' ) +
1236 " actual state = " +
1237 intents.get( 'state' ) +
1238 " does not equal expected states = "
1239 + str( expectedState ) )
1240 returnValue = main.FALSE
1241
1242 if returnValue == main.TRUE:
1243 main.log.info( self.name + ": All " +
1244 str( len( intentsDict ) ) +
1245 " intents are in " + str( expectedState ) +
1246 " state" )
1247 return returnValue
Jon Halle401b092015-09-23 13:34:24 -07001248 except ( AttributeError, TypeError ):
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001249 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001250 return None
Jon Halle401b092015-09-23 13:34:24 -07001251 except Exception:
1252 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001253 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001254
Jeremy Songster306ed7a2016-07-19 10:59:07 -07001255 def flows( self, ip="DEFAULT", port="DEFAULT", subjectClass=None, subjectKey=None ):
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001256 """
1257 Description:
1258 Get flows currently added to the system
1259 NOTE:
1260 The flows -j cli command has completely different format than
Jon Halle401b092015-09-23 13:34:24 -07001261 the REST output
1262
1263 Returns None for exception
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001264 """
1265 try:
1266 output = None
Jeremy Songster306ed7a2016-07-19 10:59:07 -07001267 url = "/flows"
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001268 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07001269 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001270 ip = self.ip_address
1271 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07001272 main.log.warn( self.name + ": No port given, reverting to port " +
Jon Hallf7234882015-08-28 13:16:31 -07001273 "from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001274 port = self.port
Jeremy Songster306ed7a2016-07-19 10:59:07 -07001275 if subjectKey and not subjectClass:
1276 main.log.warning( "Subject Key provided without Subject Class. Ignoring Subject Key" )
1277 if subjectClass:
1278 url += "/" + subjectClass
1279 if subjectKey:
1280 url += "/" + subjectKey
1281 response = self.send( url=url, ip=ip, port=port )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001282 if response:
1283 if 200 <= response[ 0 ] <= 299:
1284 output = response[ 1 ]
1285 a = json.loads( output ).get( 'flows' )
Jon Halle401b092015-09-23 13:34:24 -07001286 assert a is not None, "Error parsing json object"
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001287 b = json.dumps( a )
1288 return b
1289 else:
Jon Hall3c0114c2020-08-11 15:07:42 -07001290 main.log.error( "Error with REST request, response was: %s: %s" %
1291 ( response[ 0 ], response[ 1 ] ) )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001292 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -07001293 except ( AttributeError, AssertionError, TypeError ):
1294 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001295 return None
Jon Halle401b092015-09-23 13:34:24 -07001296 except Exception:
1297 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001298 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001299
Jon Halle401b092015-09-23 13:34:24 -07001300 def getFlows( self, deviceId, flowId=None, ip="DEFAULT", port="DEFAULT" ):
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001301 """
1302 Description:
1303 Gets all the flows of the device or get a specific flow in the
1304 device by giving its flow ID
1305 Required:
Jon Halle401b092015-09-23 13:34:24 -07001306 str deviceId - device/switch Id
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001307 Optional:
1308 int/hex flowId - ID of the flow
1309 """
1310 try:
1311 output = None
1312 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07001313 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001314 ip = self.ip_address
1315 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07001316 main.log.warn( self.name + ": No port given, reverting to port " +
Jon Hallf7234882015-08-28 13:16:31 -07001317 "from topo file" )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001318 port = self.port
Jon Halle401b092015-09-23 13:34:24 -07001319 url = "/flows/" + deviceId
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001320 if flowId:
1321 url += "/" + str( int( flowId ) )
1322 print url
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001323 response = self.send( url=url, ip = ip, port = port )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001324 if response:
1325 if 200 <= response[ 0 ] <= 299:
1326 output = response[ 1 ]
1327 a = json.loads( output ).get( 'flows' )
Jon Halle401b092015-09-23 13:34:24 -07001328 assert a is not None, "Error parsing json object"
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001329 b = json.dumps( a )
1330 return b
1331 else:
Jon Hall3c0114c2020-08-11 15:07:42 -07001332 main.log.error( "Error with REST request, response was: %s: %s" %
1333 ( response[ 0 ], response[ 1 ] ) )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001334 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -07001335 except ( AttributeError, AssertionError, TypeError ):
1336 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001337 return None
Jon Halle401b092015-09-23 13:34:24 -07001338 except Exception:
1339 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001340 main.cleanAndExit()
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001341
GlennRC073e8bc2015-10-27 17:11:28 -07001342 def sendFlow( self, deviceId, flowJson, ip="DEFAULT", port="DEFAULT", debug=False ):
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001343 """
1344 Description:
GlennRC073e8bc2015-10-27 17:11:28 -07001345 Sends a single flow to the specified device. This function exists
1346 so you can bypass the addFLow driver and send your own custom flow.
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001347 Required:
GlennRC073e8bc2015-10-27 17:11:28 -07001348 * The flow in json
1349 * the device id to add the flow to
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001350 Returns:
1351 Returns main.TRUE for successful requests; Returns main.FALSE
1352 if error on requests;
1353 Returns None for exceptions
1354 NOTE:
1355 The ip and port option are for the requests input's ip and port
1356 of the ONOS node
1357 """
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001358
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001359 try:
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001360 if debug:
Jon Hall3c0114c2020-08-11 15:07:42 -07001361 main.log.debug( self.name + ": Adding flow: " + self.pprint( flowJson ) )
1362 response = None
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001363 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07001364 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001365 ip = self.ip_address
1366 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07001367 main.log.warn( self.name + ": No port given, reverting to port " +
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001368 "from topo file" )
1369 port = self.port
1370 url = "/flows/" + deviceId
suibin zhang116647a2016-05-06 16:30:09 -07001371 response = self.send( method="POST",
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001372 url=url, ip = ip, port = port,
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001373 data=json.dumps( flowJson ) )
1374 if response:
Ming Yan Shuab2f7f52016-08-03 15:21:24 -07001375 if "201" in str( response[ 0 ] ):
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001376 main.log.info( self.name + ": Successfully POST flow" +
1377 "in device: " + str( deviceId ) )
1378 return main.TRUE
1379 else:
Jon Hall3c0114c2020-08-11 15:07:42 -07001380 main.log.error( "Error with REST request, response was: %s: %s" %
1381 ( response[ 0 ], response[ 1 ] ) )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001382 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -07001383 except NotImplementedError as e:
1384 raise e # Inform the caller
1385 except ( AttributeError, TypeError ):
1386 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001387 return None
Jon Halle401b092015-09-23 13:34:24 -07001388 except Exception:
1389 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001390 main.cleanAndExit()
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001391
GlennRC073e8bc2015-10-27 17:11:28 -07001392 def addFlow( self,
1393 deviceId,
1394 appId=0,
1395 ingressPort="",
1396 egressPort="",
1397 ethType="",
1398 ethSrc="",
1399 ethDst="",
1400 vlan="",
1401 ipProto="",
1402 ipSrc=(),
1403 ipDst=(),
1404 tcpSrc="",
1405 tcpDst="",
GlennRC956ea742015-11-05 16:14:15 -08001406 udpDst="",
1407 udpSrc="",
1408 mpls="",
alisone14d7b02016-07-06 10:31:51 -07001409 priority=100,
kavitha Alagesan373e0552016-11-22 05:22:05 +05301410 groupId="",
GlennRC073e8bc2015-10-27 17:11:28 -07001411 ip="DEFAULT",
1412 port="DEFAULT",
1413 debug=False ):
1414 """
1415 Description:
1416 Creates a single flow in the specified device
1417 Required:
1418 * deviceId: id of the device
1419 Optional:
1420 * ingressPort: port ingress device
1421 * egressPort: port of egress device
1422 * ethType: specify ethType
1423 * ethSrc: specify ethSrc ( i.e. src mac addr )
1424 * ethDst: specify ethDst ( i.e. dst mac addr )
1425 * ipProto: specify ip protocol
1426 * ipSrc: specify ip source address with mask eg. ip#/24
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001427 as a tuple (type, ip#)
GlennRC073e8bc2015-10-27 17:11:28 -07001428 * ipDst: specify ip destination address eg. ip#/24
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001429 as a tuple (type, ip#)
GlennRC073e8bc2015-10-27 17:11:28 -07001430 * tcpSrc: specify tcp source port
1431 * tcpDst: specify tcp destination port
1432 Returns:
1433 Returns main.TRUE for successful requests; Returns main.FALSE
1434 if error on requests;
1435 Returns None for exceptions
1436 NOTE:
1437 The ip and port option are for the requests input's ip and port
1438 of the ONOS node
1439 """
1440 try:
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001441 flowJson = { "priority": priority,
1442 "isPermanent": "true",
1443 "timeout": 0,
1444 "deviceId": deviceId,
1445 "treatment": { "instructions": [] },
1446 "selector": { "criteria": [] }}
GlennRC073e8bc2015-10-27 17:11:28 -07001447 if appId:
1448 flowJson[ "appId" ] = appId
kavitha Alagesan373e0552016-11-22 05:22:05 +05301449
1450 if groupId:
1451 flowJson[ 'treatment' ][ 'instructions' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001452 "type": "GROUP",
1453 "groupId": groupId } )
kavitha Alagesan373e0552016-11-22 05:22:05 +05301454
GlennRC073e8bc2015-10-27 17:11:28 -07001455 if egressPort:
1456 flowJson[ 'treatment' ][ 'instructions' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001457 "type": "OUTPUT",
1458 "port": egressPort } )
GlennRC073e8bc2015-10-27 17:11:28 -07001459 if ingressPort:
1460 flowJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001461 "type": "IN_PORT",
1462 "port": ingressPort } )
GlennRC073e8bc2015-10-27 17:11:28 -07001463 if ethType:
1464 flowJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001465 "type": "ETH_TYPE",
1466 "ethType": ethType } )
GlennRC073e8bc2015-10-27 17:11:28 -07001467 if ethSrc:
1468 flowJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001469 "type": "ETH_SRC",
1470 "mac": ethSrc } )
GlennRC073e8bc2015-10-27 17:11:28 -07001471 if ethDst:
1472 flowJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001473 "type": "ETH_DST",
1474 "mac": ethDst } )
GlennRC073e8bc2015-10-27 17:11:28 -07001475 if vlan:
1476 flowJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001477 "type": "VLAN_VID",
1478 "vlanId": vlan } )
GlennRC956ea742015-11-05 16:14:15 -08001479 if mpls:
1480 flowJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001481 "type": "MPLS_LABEL",
1482 "label": mpls } )
GlennRC073e8bc2015-10-27 17:11:28 -07001483 if ipSrc:
1484 flowJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001485 "type": ipSrc[ 0 ],
1486 "ip": ipSrc[ 1 ] } )
GlennRC073e8bc2015-10-27 17:11:28 -07001487 if ipDst:
1488 flowJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001489 "type": ipDst[ 0 ],
1490 "ip": ipDst[ 1 ] } )
GlennRC073e8bc2015-10-27 17:11:28 -07001491 if tcpSrc:
1492 flowJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001493 "type": "TCP_SRC",
GlennRC073e8bc2015-10-27 17:11:28 -07001494 "tcpPort": tcpSrc } )
1495 if tcpDst:
1496 flowJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001497 "type": "TCP_DST",
GlennRC073e8bc2015-10-27 17:11:28 -07001498 "tcpPort": tcpDst } )
GlennRC956ea742015-11-05 16:14:15 -08001499 if udpSrc:
1500 flowJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001501 "type": "UDP_SRC",
GlennRC956ea742015-11-05 16:14:15 -08001502 "udpPort": udpSrc } )
1503 if udpDst:
1504 flowJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001505 "type": "UDP_DST",
GlennRC956ea742015-11-05 16:14:15 -08001506 "udpPort": udpDst } )
GlennRC073e8bc2015-10-27 17:11:28 -07001507 if ipProto:
1508 flowJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001509 "type": "IP_PROTO",
GlennRC073e8bc2015-10-27 17:11:28 -07001510 "protocol": ipProto } )
1511
Jeremy Ronquillo29260cd2017-10-13 13:30:54 -07001512 return self.sendFlow( deviceId=deviceId, flowJson=flowJson, debug=debug, ip=ip, port=port )
GlennRC073e8bc2015-10-27 17:11:28 -07001513
1514 except ( AttributeError, TypeError ):
1515 main.log.exception( self.name + ": Object not as expected" )
1516 return None
1517 except Exception:
1518 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001519 main.cleanAndExit()
GlennRC073e8bc2015-10-27 17:11:28 -07001520
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001521 def removeFlow( self, deviceId, flowId,
1522 ip="DEFAULT", port="DEFAULT" ):
1523 """
1524 Description:
1525 Remove specific device flow
1526 Required:
1527 str deviceId - id of the device
1528 str flowId - id of the flow
1529 Return:
1530 Returns main.TRUE if successfully deletes flows, otherwise
1531 Returns main.FALSE, Returns None on error
1532 """
1533 try:
Jon Hall3c0114c2020-08-11 15:07:42 -07001534 response = None
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001535 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07001536 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001537 ip = self.ip_address
1538 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07001539 main.log.warn( self.name + ": No port given, reverting to port " +
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001540 "from topo file" )
1541 port = self.port
1542 # NOTE: REST url requires the intent id to be in decimal form
1543 query = "/" + str( deviceId ) + "/" + str( int( flowId ) )
suibin zhang116647a2016-05-06 16:30:09 -07001544 response = self.send( method="DELETE",
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001545 url="/flows" + query, ip = ip, port = port )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001546 if response:
1547 if 200 <= response[ 0 ] <= 299:
1548 return main.TRUE
1549 else:
Jon Hall3c0114c2020-08-11 15:07:42 -07001550 main.log.error( "Error with REST request, response was: %s: %s" %
1551 ( response[ 0 ], response[ 1 ] ) )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001552 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -07001553 except ( AttributeError, TypeError ):
1554 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001555 return None
Jon Halle401b092015-09-23 13:34:24 -07001556 except Exception:
1557 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001558 main.cleanAndExit()
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001559
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001560 def checkFlowsState( self , ip="DEFAULT", port="DEFAULT" ):
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001561 """
1562 Description:
1563 Check if all the current flows are in ADDED state
1564 Return:
1565 returnValue - Returns main.TRUE only if all flows are in
1566 return main.FALSE otherwise;
1567 Returns None for exception
1568 """
1569 try:
1570 tempFlows = json.loads( self.flows( ip=ip, port=port ) )
1571 returnValue = main.TRUE
1572 for flow in tempFlows:
1573 if flow.get( 'state' ) != 'ADDED':
1574 main.log.info( self.name + ": flow Id: " +
1575 str( flow.get( 'groupId' ) ) +
1576 " | state:" +
1577 str( flow.get( 'state' ) ) )
1578 returnValue = main.FALSE
1579 return returnValue
Jon Halle401b092015-09-23 13:34:24 -07001580 except ( AttributeError, TypeError ):
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001581 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001582 return None
1583 except Exception:
1584 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001585 main.cleanAndExit()
Jon Hall66e001c2015-11-12 09:45:10 -08001586
1587 def getNetCfg( self, ip="DEFAULT", port="DEFAULT",
1588 subjectClass=None, subjectKey=None, configKey=None ):
1589 """
1590 Description:
1591 Get a json object with the ONOS network configurations
1592 Returns:
1593 A json object containing the network configuration in
1594 ONOS; Returns main.FALSE if error on requests;
1595 Returns None for exception
1596 """
1597 try:
1598 output = None
1599 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07001600 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
Jon Hall66e001c2015-11-12 09:45:10 -08001601 ip = self.ip_address
1602 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07001603 main.log.warn( self.name + ": No port given, reverting to port " +
Jon Hall66e001c2015-11-12 09:45:10 -08001604 "from topo file" )
1605 port = self.port
1606 url = "/network/configuration"
1607 if subjectClass:
Siddesh606bd872021-06-29 23:42:36 +00001608 url += "/" + self.checkRegex( subjectClass )
Jon Hall66e001c2015-11-12 09:45:10 -08001609 if subjectKey:
Siddesh606bd872021-06-29 23:42:36 +00001610 url += "/" + self.checkRegex( subjectKey )
Jon Hall66e001c2015-11-12 09:45:10 -08001611 if configKey:
Siddesh606bd872021-06-29 23:42:36 +00001612 url += "/" + self.checkRegex( configKey )
1613 url = requests.utils.quote( url, safe="%/" )
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001614 response = self.send( url=url, ip = ip, port = port )
Jon Hall66e001c2015-11-12 09:45:10 -08001615 if response:
1616 if 200 <= response[ 0 ] <= 299:
1617 output = response[ 1 ]
1618 a = json.loads( output )
1619 b = json.dumps( a )
1620 return b
1621 elif response[ 0 ] == 404:
1622 main.log.error( "Requested configuration doesn't exist: " +
Jon Hall3c0114c2020-08-11 15:07:42 -07001623 ( response[ 0 ], response[ 1 ] ) )
Jon Hall66e001c2015-11-12 09:45:10 -08001624 return {}
1625 else:
Jon Hall3c0114c2020-08-11 15:07:42 -07001626 main.log.error( "Error with REST request, response was: %s: %s" %
1627 ( response[ 0 ], response[ 1 ] ) )
Jon Hall66e001c2015-11-12 09:45:10 -08001628 return main.FALSE
1629 except ( AttributeError, TypeError ):
1630 main.log.exception( self.name + ": Object not as expected" )
1631 return None
1632 except Exception:
1633 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001634 main.cleanAndExit()
Jon Hall66e001c2015-11-12 09:45:10 -08001635
Siddesh606bd872021-06-29 23:42:36 +00001636 def checkRegex( self, inputStr ):
1637 res = inputStr.replace('/', '%2f')
1638 return res
1639
Jon Hall66e001c2015-11-12 09:45:10 -08001640 def setNetCfg( self, cfgJson, ip="DEFAULT", port="DEFAULT",
1641 subjectClass=None, subjectKey=None, configKey=None ):
1642 """
1643 Description:
1644 Set a json object with the ONOS network configurations
1645 Returns:
1646 Returns main.TRUE for successful requests; Returns main.FALSE
1647 if error on requests;
1648 Returns None for exceptions
1649
1650 """
1651 try:
Jon Hall3c0114c2020-08-11 15:07:42 -07001652 response = None
Jon Hall66e001c2015-11-12 09:45:10 -08001653 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07001654 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
Jon Hall66e001c2015-11-12 09:45:10 -08001655 ip = self.ip_address
1656 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07001657 main.log.warn( self.name + ": No port given, reverting to port " +
Jon Hall66e001c2015-11-12 09:45:10 -08001658 "from topo file" )
1659 port = self.port
1660 url = "/network/configuration"
1661 if subjectClass:
Siddesh606bd872021-06-29 23:42:36 +00001662 url += "/" + self.checkRegex( subjectClass )
Jon Hall66e001c2015-11-12 09:45:10 -08001663 if subjectKey:
Siddesh606bd872021-06-29 23:42:36 +00001664 url += "/" + self.checkRegex( subjectKey )
Jon Hall66e001c2015-11-12 09:45:10 -08001665 if configKey:
Siddesh606bd872021-06-29 23:42:36 +00001666 url += "/" + self.checkRegex( configKey )
1667 url = requests.utils.quote( url, safe="%/" )
suibin zhang116647a2016-05-06 16:30:09 -07001668 response = self.send( method="POST",
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001669 url=url, ip = ip, port = port,
Jon Hall66e001c2015-11-12 09:45:10 -08001670 data=json.dumps( cfgJson ) )
1671 if response:
1672 if 200 <= response[ 0 ] <= 299:
1673 main.log.info( self.name + ": Successfully POST cfg" )
1674 return main.TRUE
1675 else:
Jon Hall3c0114c2020-08-11 15:07:42 -07001676 main.log.error( "Error with REST request, response was: %s: %s" %
1677 ( response[ 0 ], response[ 1 ] ) )
Jon Hall66e001c2015-11-12 09:45:10 -08001678 return main.FALSE
1679 except ( AttributeError, TypeError ):
1680 main.log.exception( self.name + ": Object not as expected" )
1681 return None
1682 except Exception:
1683 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001684 main.cleanAndExit()
Jon Hall66e001c2015-11-12 09:45:10 -08001685
1686 def removeNetCfg( self, ip="DEFAULT", port="DEFAULT",
1687 subjectClass=None, subjectKey=None, configKey=None ):
1688 """
1689 Description:
1690 Remove a json object from the ONOS network configurations
1691 Returns:
1692 Returns main.TRUE for successful requests; Returns main.FALSE
1693 if error on requests;
1694 Returns None for exceptions
1695
1696 """
1697 try:
Jon Hall3c0114c2020-08-11 15:07:42 -07001698 response = None
Jon Hall66e001c2015-11-12 09:45:10 -08001699 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07001700 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
Jon Hall66e001c2015-11-12 09:45:10 -08001701 ip = self.ip_address
1702 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07001703 main.log.warn( self.name + ": No port given, reverting to port " +
Jon Hall66e001c2015-11-12 09:45:10 -08001704 "from topo file" )
1705 port = self.port
1706 url = "/network/configuration"
1707 if subjectClass:
1708 url += "/" + subjectClass
1709 if subjectKey:
1710 url += "/" + subjectKey
1711 if configKey:
1712 url += "/" + configKey
suibin zhang116647a2016-05-06 16:30:09 -07001713 response = self.send( method="DELETE",
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001714 url=url, ip = ip, port = port )
Jon Hall66e001c2015-11-12 09:45:10 -08001715 if response:
1716 if 200 <= response[ 0 ] <= 299:
1717 main.log.info( self.name + ": Successfully delete cfg" )
1718 return main.TRUE
1719 else:
Jon Hall3c0114c2020-08-11 15:07:42 -07001720 main.log.error( "Error with REST request, response was: %s: %s" %
1721 ( response[ 0 ], response[ 1 ] ) )
Jon Hall66e001c2015-11-12 09:45:10 -08001722 return main.FALSE
1723 except ( AttributeError, TypeError ):
1724 main.log.exception( self.name + ": Object not as expected" )
1725 return None
1726 except Exception:
1727 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001728 main.cleanAndExit()
suibin zhang17308622016-04-14 15:45:30 -07001729
Jon Hall10e2ab82020-09-15 17:14:54 -07001730 def getXconnect( self, ip="DEFAULT", port="DEFAULT" ):
1731 """
1732 Description:
1733 Get xconnects
1734 Returns:
1735 Return xconnects json object
1736 Returns None for exceptions
1737
1738 """
1739 try:
1740 base = "/onos/segmentrouting"
1741 response = None
1742 if ip == "DEFAULT":
1743 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
1744 ip = self.ip_address
1745 if port == "DEFAULT":
1746 main.log.warn( self.name + ": No port given, reverting to port " +
1747 "from topo file" )
1748 port = self.port
1749 url = "/xconnect"
1750 response = self.send( method="GET",
1751 base=base,
1752 url=url, ip = ip, port = port )
1753 if response:
1754 if 200 <= response[ 0 ] <= 299:
1755 main.log.info( self.name + ": Successfully POST cfg" )
1756 return main.TRUE
1757 else:
1758 main.log.error( "Error with REST request, response was: %s: %s" %
1759 ( response[ 0 ], response[ 1 ] ) )
1760 return main.FALSE
1761 except ( AttributeError, TypeError ):
1762 main.log.exception( self.name + ": Object not as expected" )
1763 return None
1764 except Exception:
1765 main.log.exception( self.name + ": Uncaught exception!" )
1766 main.cleanAndExit()
1767
1768 def setXconnect( self, deviceId, vlanId, port1, port2, ip="DEFAULT", port="DEFAULT" ):
1769 """
1770 Description:
1771 Set xconnects
1772 Returns:
1773 Returns main.TRUE for successful requests; Returns main.FALSE
1774 if error on requests;
1775 Returns None for exceptions
1776
1777 """
1778 try:
1779 cfgJson = json.loads( '{"deviceId": "%s", "vlanId": "%s", "endpoints":[%s,%s]}' %
1780 ( deviceId, vlanId, port1, port2 ) )
1781 response = self.setXconnectJson( cfgJson, ip=ip, port=port )
1782 except ( AttributeError, TypeError ):
1783 main.log.exception( self.name + ": Object not as expected" )
1784 return None
1785 except Exception:
1786 main.log.exception( self.name + ": Uncaught exception!" )
1787 main.cleanAndExit()
1788
1789 def setXconnectJson( self, cfgJson, ip="DEFAULT", port="DEFAULT" ):
1790 """
1791 Description:
1792 Set xconnects
1793 Returns:
1794 Returns main.TRUE for successful requests; Returns main.FALSE
1795 if error on requests;
1796 Returns None for exceptions
1797
1798 """
1799 try:
1800 base = "/onos/segmentrouting"
1801 response = None
1802 if ip == "DEFAULT":
1803 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
1804 ip = self.ip_address
1805 if port == "DEFAULT":
1806 main.log.warn( self.name + ": No port given, reverting to port " +
1807 "from topo file" )
1808 port = self.port
1809 url = "/xconnect"
1810 response = self.send( method="POST",
1811 base=base,
1812 url=url, ip = ip, port = port,
1813 data=json.dumps( cfgJson ) )
1814 if response:
1815 if 200 <= response[ 0 ] <= 299:
1816 main.log.info( self.name + ": Successfully POST cfg" )
1817 return main.TRUE
1818 else:
1819 main.log.error( "Error with REST request, response was: %s: %s" %
1820 ( response[ 0 ], response[ 1 ] ) )
1821 return main.FALSE
1822 except ( AttributeError, TypeError ):
1823 main.log.exception( self.name + ": Object not as expected" )
1824 return None
1825 except Exception:
1826 main.log.exception( self.name + ": Uncaught exception!" )
1827 main.cleanAndExit()
1828
1829 def deleteXconnect( self, cfgJson, ip="DEFAULT", port="DEFAULT" ):
1830 """
1831 Description:
1832 Remove xconnects
1833 Returns:
1834 Returns main.TRUE for successful requests; Returns main.FALSE
1835 if error on requests;
1836 Returns None for exceptions
1837
1838 """
1839 try:
1840 base = "/onos/segmentrouting"
1841 response = None
1842 if ip == "DEFAULT":
1843 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
1844 ip = self.ip_address
1845 if port == "DEFAULT":
1846 main.log.warn( self.name + ": No port given, reverting to port " +
1847 "from topo file" )
1848 port = self.port
1849 url = "/xconnect"
1850 response = self.send( method="DELETE",
1851 base=base,
1852 url=url, ip = ip, port = port,
1853 data=json.dumps( cfgJson ) )
1854 if response:
1855 if 200 <= response[ 0 ] <= 299:
1856 main.log.info( self.name + ": Successfully POST cfg" )
1857 return main.TRUE
1858 else:
1859 main.log.error( "Error with REST request, response was: %s: %s" %
1860 ( response[ 0 ], response[ 1 ] ) )
1861 return main.FALSE
1862 except ( AttributeError, TypeError ):
1863 main.log.exception( self.name + ": Object not as expected" )
1864 return None
1865 except Exception:
1866 main.log.exception( self.name + ": Uncaught exception!" )
1867 main.cleanAndExit()
1868
suibin zhang17308622016-04-14 15:45:30 -07001869 def createFlowBatch( self,
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001870 numSw = 1,
1871 swIndex = 1,
1872 batchSize = 1,
1873 batchIndex = 1,
1874 deviceIdpreFix = "of:",
1875 appId=0,
1876 deviceID="",
1877 ingressPort="",
1878 egressPort="",
1879 ethType="",
1880 ethSrc="",
1881 ethDst="",
1882 vlan="",
1883 ipProto="",
1884 ipSrc=(),
1885 ipDst=(),
1886 tcpSrc="",
1887 tcpDst="",
1888 udpDst="",
1889 udpSrc="",
1890 mpls="",
1891 ip="DEFAULT",
1892 port="DEFAULT",
1893 debug=False ):
suibin zhang17308622016-04-14 15:45:30 -07001894 """
1895 Description:
1896 Creates batches of MAC-rule flows for POST.
1897 Predefined MAC: 2 MS Hex digit for iterating devices
1898 Next 5 Hex digit for iterating batch numbers
1899 Next 5 Hex digit for iterating flows within a batch
1900 Required:
1901 * deviceId: id of the device
1902 Optional:
1903 * ingressPort: port ingress device
1904 * egressPort: port of egress device
1905 * ethType: specify ethType
1906 * ethSrc: specify ethSrc ( i.e. src mac addr )
1907 * ethDst: specify ethDst ( i.e. dst mac addr )
1908 * ipProto: specify ip protocol
1909 * ipSrc: specify ip source address with mask eg. ip#/24
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001910 as a tuple (type, ip#)
suibin zhang17308622016-04-14 15:45:30 -07001911 * ipDst: specify ip destination address eg. ip#/24
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001912 as a tuple (type, ip#)
suibin zhang17308622016-04-14 15:45:30 -07001913 * tcpSrc: specify tcp source port
1914 * tcpDst: specify tcp destination port
1915 Returns:
1916 Returns main.TRUE for successful requests; Returns main.FALSE
1917 if error on requests;
1918 Returns None for exceptions
1919 NOTE:
1920 The ip and port option are for the requests input's ip and port
1921 of the ONOS node
1922 """
suibin zhang17308622016-04-14 15:45:30 -07001923
1924 flowJsonList = []
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001925 flowJsonBatch = { "flows": flowJsonList }
suibin zhang17308622016-04-14 15:45:30 -07001926 dev = swIndex
1927
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001928 for fl in range( 1, batchSize + 1 ):
1929 flowJson = { "priority": 100,
1930 "deviceId": "",
1931 "isPermanent": "true",
1932 "timeout": 0,
1933 "treatment": { "instructions": [] },
1934 "selector": { "criteria": [] }}
suibin zhang17308622016-04-14 15:45:30 -07001935
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001936 # main.log.info("fl: " + str(fl))
suibin zhang17308622016-04-14 15:45:30 -07001937 if dev <= numSw:
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001938 deviceId = deviceIdpreFix + "{0:0{1}x}".format( dev, 16 )
1939 # print deviceId
1940 flowJson[ 'deviceId' ] = deviceId
suibin zhang17308622016-04-14 15:45:30 -07001941 dev += 1
1942 else:
1943 dev = 1
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001944 deviceId = deviceIdpreFix + "{0:0{1}x}".format( dev, 16 )
1945 # print deviceId
1946 flowJson[ 'deviceId' ] = deviceId
suibin zhang17308622016-04-14 15:45:30 -07001947 dev += 1
1948
1949 # ethSrc starts with "0"; ethDst starts with "1"
1950 # 2 Hex digit of device number; 5 digits of batch index number; 5 digits of batch size
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001951 ethS = "%02X" % int( "0" + "{0:0{1}b}".format( dev, 7 ), 2 ) + \
1952 "{0:0{1}x}".format( batchIndex, 5 ) + "{0:0{1}x}".format( fl, 5 )
1953 ethSrc = ':'.join( ethS[ i: i+2 ] for i in range( 0, len( ethS ), 2 ) )
1954 ethD = "%02X" % int( "1" + "{0:0{1}b}".format( dev, 7 ), 2 ) + \
1955 "{0:0{1}x}".format( batchIndex, 5 ) + "{0:0{1}x}".format( fl, 5 )
1956 ethDst = ':'.join( ethD[ i: i+2 ] for i in range( 0, len( ethD ), 2 ) )
suibin zhang17308622016-04-14 15:45:30 -07001957
1958 if appId:
1959 flowJson[ "appId" ] = appId
1960
1961 if egressPort:
1962 flowJson[ 'treatment' ][ 'instructions' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001963 "type": "OUTPUT",
1964 "port": egressPort } )
suibin zhang17308622016-04-14 15:45:30 -07001965 if ingressPort:
1966 flowJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001967 "type": "IN_PORT",
1968 "port": ingressPort } )
suibin zhang17308622016-04-14 15:45:30 -07001969 if ethType:
1970 flowJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001971 "type": "ETH_TYPE",
1972 "ethType": ethType } )
suibin zhang17308622016-04-14 15:45:30 -07001973 if ethSrc:
1974 flowJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001975 "type": "ETH_SRC",
1976 "mac": ethSrc } )
suibin zhang17308622016-04-14 15:45:30 -07001977 if ethDst:
1978 flowJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001979 "type": "ETH_DST",
1980 "mac": ethDst } )
suibin zhang17308622016-04-14 15:45:30 -07001981 if vlan:
1982 flowJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001983 "type": "VLAN_VID",
1984 "vlanId": vlan } )
suibin zhang17308622016-04-14 15:45:30 -07001985 if mpls:
1986 flowJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001987 "type": "MPLS_LABEL",
1988 "label": mpls } )
suibin zhang17308622016-04-14 15:45:30 -07001989 if ipSrc:
1990 flowJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001991 "type": ipSrc[ 0 ],
1992 "ip": ipSrc[ 1 ] } )
suibin zhang17308622016-04-14 15:45:30 -07001993 if ipDst:
1994 flowJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001995 "type": ipDst[ 0 ],
1996 "ip": ipDst[ 1 ] } )
suibin zhang17308622016-04-14 15:45:30 -07001997 if tcpSrc:
1998 flowJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07001999 "type": "TCP_SRC",
suibin zhang17308622016-04-14 15:45:30 -07002000 "tcpPort": tcpSrc } )
2001 if tcpDst:
2002 flowJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07002003 "type": "TCP_DST",
suibin zhang17308622016-04-14 15:45:30 -07002004 "tcpPort": tcpDst } )
2005 if udpSrc:
2006 flowJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07002007 "type": "UDP_SRC",
suibin zhang17308622016-04-14 15:45:30 -07002008 "udpPort": udpSrc } )
2009 if udpDst:
2010 flowJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07002011 "type": "UDP_DST",
suibin zhang17308622016-04-14 15:45:30 -07002012 "udpPort": udpDst } )
2013 if ipProto:
2014 flowJson[ 'selector' ][ 'criteria' ].append( {
Jeremy Ronquillo82705492017-10-18 14:19:55 -07002015 "type": "IP_PROTO",
suibin zhang17308622016-04-14 15:45:30 -07002016 "protocol": ipProto } )
Jeremy Ronquillo82705492017-10-18 14:19:55 -07002017 flowJsonList.append( flowJson )
suibin zhang17308622016-04-14 15:45:30 -07002018
Jon Hall3c0114c2020-08-11 15:07:42 -07002019 main.log.info( self.name + ": Number of flows in batch: " + str( len( flowJsonList ) ) )
Jeremy Ronquillo82705492017-10-18 14:19:55 -07002020 flowJsonBatch[ 'flows' ] = flowJsonList
suibin zhang17308622016-04-14 15:45:30 -07002021
2022 return flowJsonBatch
2023
suibin zhang17308622016-04-14 15:45:30 -07002024 def sendFlowBatch( self, batch={}, ip="DEFAULT", port="DEFAULT", debug=False ):
2025 """
2026 Description:
2027 Sends a single flow batch through /flows REST API.
2028 Required:
2029 * The batch of flows
2030 Returns:
2031 Returns main.TRUE for successful requests; Returns main.FALSE
2032 if error on requests;
2033 Returns None for exceptions
2034 NOTE:
2035 The ip and port option are for the requests input's ip and port
2036 of the ONOS node
2037 """
suibin zhang17308622016-04-14 15:45:30 -07002038
2039 try:
Jeremy Ronquillo82705492017-10-18 14:19:55 -07002040 if debug:
Jon Hall3c0114c2020-08-11 15:07:42 -07002041 main.log.debug( self.name + ": Adding flow: " + self.pprint( batch ) )
2042 response = None
suibin zhang17308622016-04-14 15:45:30 -07002043 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07002044 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
suibin zhang17308622016-04-14 15:45:30 -07002045 ip = self.ip_address
2046 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07002047 main.log.warn( self.name + ": No port given, reverting to port " +
suibin zhang17308622016-04-14 15:45:30 -07002048 "from topo file" )
2049 port = self.port
2050 url = "/flows/"
suibin zhang116647a2016-05-06 16:30:09 -07002051 response = self.send( method="POST",
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00002052 url=url, ip = ip, port = port,
suibin zhang17308622016-04-14 15:45:30 -07002053 data=json.dumps( batch ) )
Jeremy Ronquillo82705492017-10-18 14:19:55 -07002054 # main.log.info("Post response is: ", str(response[0]))
2055 if response[ 0 ] == 200:
suibin zhang17308622016-04-14 15:45:30 -07002056 main.log.info( self.name + ": Successfully POST flow batch" )
2057 return main.TRUE, response
2058 else:
Jon Hall3c0114c2020-08-11 15:07:42 -07002059 main.log.error( "Error with REST request, response was: %s: %s" %
2060 ( response[ 0 ], response[ 1 ] ) )
You Wang7b5b2262016-11-10 13:54:56 -08002061 return main.FALSE, response
suibin zhang17308622016-04-14 15:45:30 -07002062 except NotImplementedError as e:
2063 raise e # Inform the caller
2064 except ( AttributeError, TypeError ):
2065 main.log.exception( self.name + ": Object not as expected" )
You Wang7b5b2262016-11-10 13:54:56 -08002066 return None, None
suibin zhang17308622016-04-14 15:45:30 -07002067 except Exception:
2068 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07002069 main.cleanAndExit()
suibin zhang17308622016-04-14 15:45:30 -07002070
2071 def removeFlowBatch( self, batch={},
Jeremy Ronquillo82705492017-10-18 14:19:55 -07002072 ip="DEFAULT", port="DEFAULT" ):
suibin zhang17308622016-04-14 15:45:30 -07002073 """
2074 Description:
2075 Remove a batch of flows
2076 Required:
2077 flow batch
2078 Return:
2079 Returns main.TRUE if successfully deletes flows, otherwise
2080 Returns main.FALSE, Returns None on error
2081 """
2082 try:
Jon Hall3c0114c2020-08-11 15:07:42 -07002083 response = None
suibin zhang17308622016-04-14 15:45:30 -07002084 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07002085 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
suibin zhang17308622016-04-14 15:45:30 -07002086 ip = self.ip_address
2087 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07002088 main.log.warn( self.name + ": No port given, reverting to port " +
suibin zhang17308622016-04-14 15:45:30 -07002089 "from topo file" )
2090 port = self.port
2091 # NOTE: REST url requires the intent id to be in decimal form
2092
suibin zhang116647a2016-05-06 16:30:09 -07002093 response = self.send( method="DELETE",
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00002094 url="/flows/", ip = ip, port = port,
Jeremy Ronquillo82705492017-10-18 14:19:55 -07002095 data = json.dumps( batch ) )
suibin zhang17308622016-04-14 15:45:30 -07002096 if response:
2097 if 200 <= response[ 0 ] <= 299:
2098 return main.TRUE
2099 else:
Jon Hall3c0114c2020-08-11 15:07:42 -07002100 main.log.error( "Error with REST request, response was: %s: %s" %
2101 ( response[ 0 ], response[ 1 ] ) )
suibin zhang17308622016-04-14 15:45:30 -07002102 return main.FALSE
2103 except ( AttributeError, TypeError ):
2104 main.log.exception( self.name + ": Object not as expected" )
2105 return None
2106 except Exception:
2107 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07002108 main.cleanAndExit()
Jeremy Songsterbc2d8ac2016-05-04 11:25:42 -07002109
2110 def getTopology( self, topologyOutput ):
2111 """
2112 Definition:
2113 Loads a json topology output
2114 Return:
2115 topology = current ONOS topology
2116 """
2117 import json
2118 try:
2119 # either onos:topology or 'topology' will work in CLI
Jeremy Ronquillo82705492017-10-18 14:19:55 -07002120 topology = json.loads( topologyOutput )
Jeremy Songsterbc2d8ac2016-05-04 11:25:42 -07002121 main.log.debug( topology )
2122 return topology
Jeremy Songsterbc2d8ac2016-05-04 11:25:42 -07002123 except Exception:
2124 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07002125 main.cleanAndExit()
Jeremy Songsterbc2d8ac2016-05-04 11:25:42 -07002126
2127 def checkStatus(
2128 self,
Devin Lim142b5342017-07-20 15:22:39 -07002129 numswitch,
2130 numlink,
Jeremy Songsterbc2d8ac2016-05-04 11:25:42 -07002131 logLevel="info" ):
2132 """
2133 Checks the number of switches & links that ONOS sees against the
2134 supplied values. By default this will report to main.log, but the
2135 log level can be specific.
2136
Devin Lim142b5342017-07-20 15:22:39 -07002137 Params: numswitch = expected number of switches
2138 numlink = expected number of links
Jeremy Songsterbc2d8ac2016-05-04 11:25:42 -07002139 logLevel = level to log to.
2140 Currently accepts 'info', 'warn' and 'report'
2141
2142 Returns: main.TRUE if the number of switches and links are correct,
2143 main.FALSE if the number of switches and links is incorrect,
2144 and main.ERROR otherwise
2145 """
2146 try:
Flavio Castro82ee2f62016-06-07 15:04:12 -07002147 topology = self.getTopology( self.topology() )
Jeremy Ronquillo82705492017-10-18 14:19:55 -07002148 # summary = self.summary()
Jeremy Songsterbc2d8ac2016-05-04 11:25:42 -07002149 if topology == {}:
2150 return main.ERROR
2151 output = ""
2152 # Is the number of switches is what we expected
2153 devices = topology.get( 'devices', False )
2154 links = topology.get( 'links', False )
Devin Lim142b5342017-07-20 15:22:39 -07002155 if devices is False or links is False:
Jeremy Songsterbc2d8ac2016-05-04 11:25:42 -07002156 return main.ERROR
Devin Lim142b5342017-07-20 15:22:39 -07002157 switchCheck = ( int( devices ) == int( numswitch ) )
Jeremy Songsterbc2d8ac2016-05-04 11:25:42 -07002158 # Is the number of links is what we expected
Devin Lim142b5342017-07-20 15:22:39 -07002159 linkCheck = ( int( links ) == int( numlink ) )
2160 if switchCheck and linkCheck:
Jeremy Songsterbc2d8ac2016-05-04 11:25:42 -07002161 # We expected the correct numbers
2162 output = output + "The number of links and switches match "\
2163 + "what was expected"
2164 result = main.TRUE
2165 else:
2166 output = output + \
2167 "The number of links and switches does not match " + \
2168 "what was expected"
2169 result = main.FALSE
2170 output = output + "\n ONOS sees %i devices" % int( devices )
Devin Lim142b5342017-07-20 15:22:39 -07002171 output = output + " (%i expected) " % int( numswitch )
Jeremy Songsterbc2d8ac2016-05-04 11:25:42 -07002172 output = output + "and %i links " % int( links )
Devin Lim142b5342017-07-20 15:22:39 -07002173 output = output + "(%i expected)" % int( numlink )
Jeremy Songsterbc2d8ac2016-05-04 11:25:42 -07002174 if logLevel == "report":
2175 main.log.report( output )
2176 elif logLevel == "warn":
2177 main.log.warn( output )
2178 else:
2179 main.log.info( output )
2180 return result
Jeremy Songsterbc2d8ac2016-05-04 11:25:42 -07002181 except Exception:
2182 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07002183 main.cleanAndExit()
kavitha Alagesan373e0552016-11-22 05:22:05 +05302184
Jon Hall3c0114c2020-08-11 15:07:42 -07002185 def addGroup( self, deviceId, groupType, bucketList, appCookie, groupId,
2186 ip="DEFAULT", port="DEFAULT", debug=False ):
kavitha Alagesan373e0552016-11-22 05:22:05 +05302187 """
2188 Description:
2189 Creates a single Group for the specified device.
2190 Required:
2191 * deviceId: id of the device
2192 * type: Type of the Group
2193 * bucketList: Buckets to be added to the group
2194 * appCookie: Cookie for the Group
2195 * groupId: Id of the Group
2196 Returns:
2197 Returns main.TRUE for successful requests; Returns main.FALSE
2198 if error on requests;
2199 Returns None for exceptions
2200 Note:
2201 The ip and port option are for the requests input's ip and port
2202 of the ONOS node
2203 """
2204 try:
2205 groupJson = { "type": groupType,
2206 "appCookie": appCookie,
2207 "groupId": groupId,
2208 "buckets": bucketList
Jeremy Ronquillo82705492017-10-18 14:19:55 -07002209 }
kavitha Alagesan373e0552016-11-22 05:22:05 +05302210 return self.sendGroup( deviceId=deviceId, groupJson=groupJson, ip="DEFAULT", port="DEFAULT", debug=False )
2211
2212 except ( AttributeError, TypeError ):
2213 main.log.exception( self.name + ": Object not as expected" )
2214 return None
2215 except Exception:
2216 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07002217 main.cleanAndExit()
kavitha Alagesan373e0552016-11-22 05:22:05 +05302218
2219 def sendGroup( self, deviceId, groupJson, ip="DEFAULT", port="DEFAULT", debug=False ):
2220 """
2221 Description:
2222 Sends a single group to the specified device.
2223 Required:
2224 * deviceId: id of the device
2225 * groupJson: the group in json
2226 Returns:
2227 Returns main.TRUE for successful requests; Returns main.FALSE
2228 if error on requests;
2229 Returns None for exceptions
2230 NOTE:
2231 The ip and port option are for the requests input's ip and port
2232 of the ONOS node
2233 """
2234 try:
Jeremy Ronquillo82705492017-10-18 14:19:55 -07002235 if debug:
Jon Hall3c0114c2020-08-11 15:07:42 -07002236 main.log.debug( self.name + ": Adding group: " + self.pprint( groupJson ) )
2237 response = None
kavitha Alagesan373e0552016-11-22 05:22:05 +05302238 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07002239 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
kavitha Alagesan373e0552016-11-22 05:22:05 +05302240 ip = self.ip_address
2241 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07002242 main.log.warn( self.name + ": No port given, reverting to port " +
kavitha Alagesan373e0552016-11-22 05:22:05 +05302243 "from topo file" )
2244 port = self.port
2245 url = "/groups/" + deviceId
2246 response = self.send( method="POST",
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00002247 url=url, ip = ip, port = port,
kavitha Alagesan373e0552016-11-22 05:22:05 +05302248 data=json.dumps( groupJson ) )
2249 if response:
2250 if "201" in str( response[ 0 ] ):
2251 main.log.info( self.name + ": Successfully POST group " +
2252 "in device: " + str( deviceId ) )
2253 return main.TRUE
2254 else:
Jon Hall3c0114c2020-08-11 15:07:42 -07002255 main.log.error( "Error with REST request, response was: %s: %s" %
2256 ( response[ 0 ], response[ 1 ] ) )
kavitha Alagesan373e0552016-11-22 05:22:05 +05302257 return main.FALSE
2258 except NotImplementedError as e:
2259 raise e # Inform the caller
2260 except ( AttributeError, TypeError ):
2261 main.log.exception( self.name + ": Object not as expected" )
2262 return None
2263 except Exception:
2264 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07002265 main.cleanAndExit()
kavitha Alagesan373e0552016-11-22 05:22:05 +05302266
2267 def getGroups( self, deviceId=None, appCookie=None, ip="DEFAULT", port="DEFAULT" ):
2268 """
2269 Description:
2270 Get all the groups or get a specific group by giving the
2271 deviceId and appCookie
2272 Optional:
2273 * deviceId: id of the Device
2274 * appCookie: Cookie of the Group
2275 Returns:
2276 Returns Groups for successful requests; Returns main.FALSE
2277 if error on requests;
2278 Returns None for exceptions
2279 NOTE:
2280 The ip and port option are for the requests input's ip and port
2281 of the ONOS node
2282 """
2283 try:
2284 output = None
2285 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07002286 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
kavitha Alagesan373e0552016-11-22 05:22:05 +05302287 ip = self.ip_address
2288 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07002289 main.log.warn( self.name + ": No port given, reverting to port " +
kavitha Alagesan373e0552016-11-22 05:22:05 +05302290 "from topo file" )
2291 port = self.port
2292 url = "/groups"
2293 if deviceId:
2294 url += "/" + deviceId
2295 if appCookie:
Jeremy Ronquillo82705492017-10-18 14:19:55 -07002296 url += "/" + appCookie
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00002297 response = self.send( url=url, ip = ip, port = port )
kavitha Alagesan373e0552016-11-22 05:22:05 +05302298 if response:
2299 if 200 <= response[ 0 ] <= 299:
2300 output = response[ 1 ]
2301 groupsJson = json.loads( output ).get( 'groups' )
2302 assert groupsJson is not None, "Error parsing json object"
2303 groups = json.dumps( groupsJson )
2304 return groups
2305 else:
Jon Hall3c0114c2020-08-11 15:07:42 -07002306 main.log.error( "Error with REST request, response was: %s: %s" %
2307 ( response[ 0 ], response[ 1 ] ) )
kavitha Alagesan373e0552016-11-22 05:22:05 +05302308 return main.FALSE
2309 except ( AttributeError, AssertionError, TypeError ):
2310 main.log.exception( self.name + ": Object not as expected" )
2311 return None
2312 except Exception:
2313 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07002314 main.cleanAndExit()
kavitha Alagesan373e0552016-11-22 05:22:05 +05302315
2316 def removeGroup( self, deviceId, appCookie,
2317 ip="DEFAULT", port="DEFAULT" ):
2318 """
2319 Description:
2320 Removes specific device group
2321 Required:
2322 * deviceId: id of the Device
2323 * appCookie: Cookie of the Group
2324 Returns:
2325 Returns main.TRUE for successful requests; Returns main.FALSE
2326 if error on requests;
2327 Returns None for exceptions
2328 NOTE:
2329 The ip and port option are for the requests input's ip and port
2330 of the ONOS node
2331
2332 """
2333 try:
Jon Hall3c0114c2020-08-11 15:07:42 -07002334 response = None
kavitha Alagesan373e0552016-11-22 05:22:05 +05302335 if ip == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07002336 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
kavitha Alagesan373e0552016-11-22 05:22:05 +05302337 ip = self.ip_address
2338 if port == "DEFAULT":
Jon Hall3c0114c2020-08-11 15:07:42 -07002339 main.log.warn( self.name + ": No port given, reverting to port " +
kavitha Alagesan373e0552016-11-22 05:22:05 +05302340 "from topo file" )
2341 port = self.port
2342 query = "/" + str( deviceId ) + "/" + str( appCookie )
2343 response = self.send( method="DELETE",
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00002344 url="/groups" + query, ip = ip, port = port )
kavitha Alagesan373e0552016-11-22 05:22:05 +05302345 if response:
2346 if 200 <= response[ 0 ] <= 299:
2347 return main.TRUE
2348 else:
Jon Hall3c0114c2020-08-11 15:07:42 -07002349 main.log.error( "Error with REST request, response was: %s: %s" %
2350 ( response[ 0 ], response[ 1 ] ) )
kavitha Alagesan373e0552016-11-22 05:22:05 +05302351 return main.FALSE
2352 except ( AttributeError, TypeError ):
2353 main.log.exception( self.name + ": Object not as expected" )
2354 return None
2355 except Exception:
2356 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07002357 main.cleanAndExit()
Jon Hall50a00012021-03-08 11:06:11 -08002358
2359 def portstats( self, ip="DEFAULT", port="DEFAULT" ):
2360 """
2361 Description:
2362 Gets the portstats for each port in ONOS
2363 Returns:
2364 A list of dicts containing device id and a list of dicts containing the
2365 port statistics for each port.
2366 Returns main.FALSE if error on request;
2367 Returns None for exception
2368 """
2369 try:
2370 output = None
2371 if ip == "DEFAULT":
2372 main.log.warn( self.name + ": No ip given, reverting to ip from topo file" )
2373 ip = self.ip_address
2374 if port == "DEFAULT":
2375 main.log.warn( self.name + ": No port given, reverting to port " +
2376 "from topo file" )
2377 port = self.port
2378 response = self.send( url="/statistics/ports", ip = ip, port = port )
2379 if response:
2380 if 200 <= response[ 0 ] <= 299:
2381 output = response[ 1 ]
2382 a = json.loads( output ).get( 'statistics' )
2383 assert a is not None, "Error parsing json object"
2384 b = json.dumps( a )
2385 return b
2386 else:
2387 main.log.error( "Error with REST request, response was: %s: %s" %
2388 ( response[ 0 ], response[ 1 ] ) )
2389 return main.FALSE
2390 except ( AttributeError, AssertionError, TypeError ):
2391 main.log.exception( self.name + ": Object not as expected" )
2392 return None
2393 except Exception:
2394 main.log.exception( self.name + ": Uncaught exception!" )
2395 main.cleanAndExit()