blob: 3e17deaf34b55ddef86671f235dca3d924c7977b [file] [log] [blame]
Jon Hallfc915882015-07-14 13:33:17 -07001#!/usr/bin/env python
2"""
3Created on 07-08-2015
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -07004Copyright 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 Hallfc915882015-07-14 13:33:17 -070029
Jon Hallfc915882015-07-14 13:33:17 -070030from drivers.common.api.controllerdriver import Controller
31
32
33class OnosRestDriver( Controller ):
34
35 def __init__( self ):
Jon Hallf7234882015-08-28 13:16:31 -070036 self.pwd = None
37 self.user_name = "user"
Devin Limdc78e202017-06-09 18:30:07 -070038 super( OnosRestDriver, self ).__init__()
Jon Hallfc915882015-07-14 13:33:17 -070039 self.ip_address = "localhost"
40 self.port = "8080"
Jon Halle401b092015-09-23 13:34:24 -070041 self.wrapped = sys.modules[ __name__ ]
Jon Hallfc915882015-07-14 13:33:17 -070042
43 def connect( self, **connectargs ):
44 try:
45 for key in connectargs:
46 vars( self )[ key ] = connectargs[ key ]
47 self.name = self.options[ 'name' ]
48 except Exception as e:
49 main.log.exception( e )
50 try:
51 if os.getenv( str( self.ip_address ) ) != None:
52 self.ip_address = os.getenv( str( self.ip_address ) )
53 else:
kelvin-onlab03eb88d2015-07-22 10:29:02 -070054 main.log.info( self.name + ": ip set to " + self.ip_address )
Jon Hallfc915882015-07-14 13:33:17 -070055 except KeyError:
56 main.log.info( "Invalid host name," +
57 "defaulting to 'localhost' instead" )
58 self.ip_address = 'localhost'
59 except Exception as inst:
60 main.log.error( "Uncaught exception: " + str( inst ) )
61
Jon Hall6040bcf2017-08-14 11:15:41 -070062 return super( OnosRestDriver, self ).connect()
Jon Hallfc915882015-07-14 13:33:17 -070063
Jon Halle401b092015-09-23 13:34:24 -070064 def pprint( self, jsonObject ):
65 """
66 Pretty Prints a json object
67
68 arguments:
69 jsonObject - a parsed json object
70 returns:
71 A formatted string for printing or None on error
72 """
73 try:
74 if isinstance( jsonObject, str ):
75 jsonObject = json.loads( jsonObject )
76 return json.dumps( jsonObject, sort_keys=True,
77 indent=4, separators=(',', ': '))
78 except ( TypeError, ValueError ):
79 main.log.exception( "Error parsing jsonObject" )
80 return None
81
suibin zhangd5b6fe42016-05-12 08:48:58 -070082 def send( self, url, ip = "DEFAULT", port = "DEFAULT", base="/onos/v1", method="GET",
Jon Hallf7234882015-08-28 13:16:31 -070083 query=None, data=None, debug=False ):
Jon Hallfc915882015-07-14 13:33:17 -070084 """
85 Arguments:
86 str ip: ONOS IP Address
87 str port: ONOS REST Port
88 str url: ONOS REST url path.
89 NOTE that this is is only the relative path. IE "/devices"
90 str base: The base url for the given REST api. Applications could
91 potentially have their own base url
92 str method: HTTP method type
kelvin-onlab03eb88d2015-07-22 10:29:02 -070093 dict query: Dictionary to be sent in the query string for
Jon Hallfc915882015-07-14 13:33:17 -070094 the request
95 dict data: Dictionary to be sent in the body of the request
96 """
97 # TODO: Authentication - simple http (user,pass) tuple
98 # TODO: should we maybe just pass kwargs straight to response?
99 # TODO: Do we need to allow for other protocols besides http?
100 # ANSWER: Not yet, but potentially https with certificates
suibin zhangd5b6fe42016-05-12 08:48:58 -0700101 if ip == "DEFAULT":
102 main.log.warn( "No ip given, reverting to ip from topo file" )
103 ip = self.ip_address
104 if port == "DEFAULT":
105 main.log.warn( "No port given, reverting to port " +
106 "from topo file" )
107 port = self.port
suibin zhang116647a2016-05-06 16:30:09 -0700108
Jon Hallfc915882015-07-14 13:33:17 -0700109 try:
110 path = "http://" + str( ip ) + ":" + str( port ) + base + url
Jon Hallf7234882015-08-28 13:16:31 -0700111 if self.user_name and self.pwd:
suibin zhangeb121c02015-11-04 12:06:38 -0800112 main.log.info("user/passwd is: " + self.user_name + "/" + self.pwd)
Jon Hallf7234882015-08-28 13:16:31 -0700113 auth = (self.user_name, self.pwd)
114 else:
115 auth=None
Jon Hallfc915882015-07-14 13:33:17 -0700116 main.log.info( "Sending request " + path + " using " +
117 method.upper() + " method." )
118 response = requests.request( method.upper(),
119 path,
120 params=query,
Jon Hallf7234882015-08-28 13:16:31 -0700121 data=data,
122 auth=auth )
123 if debug:
124 main.log.debug( response )
Jon Hallfc915882015-07-14 13:33:17 -0700125 return ( response.status_code, response.text.encode( 'utf8' ) )
126 except requests.exceptions:
127 main.log.exception( "Error sending request." )
128 return None
Jon Halle401b092015-09-23 13:34:24 -0700129 except Exception:
130 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700131 main.cleanAndExit()
Jon Hallfc915882015-07-14 13:33:17 -0700132
133 def intents( self, ip="DEFAULT", port="DEFAULT" ):
134 """
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700135 Description:
136 Gets a list of dictionary of all intents in the system
137 Returns:
138 A list of dictionary of intents in string type to match the cli
139 version for now; Returns main.FALSE if error on request;
140 Returns None for exception
Jon Hallfc915882015-07-14 13:33:17 -0700141 """
142 try:
143 output = None
144 if ip == "DEFAULT":
145 main.log.warn( "No ip given, reverting to ip from topo file" )
146 ip = self.ip_address
147 if port == "DEFAULT":
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700148 main.log.warn( "No port given, reverting to port " +
149 "from topo file" )
Jon Hallfc915882015-07-14 13:33:17 -0700150 port = self.port
suibin zhangd5b6fe42016-05-12 08:48:58 -0700151 response = self.send( url="/intents", ip = ip, port = port )
Jon Hallfc915882015-07-14 13:33:17 -0700152 if response:
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700153 if 200 <= response[ 0 ] <= 299:
154 output = response[ 1 ]
155 a = json.loads( output ).get( 'intents' )
Jon Halle401b092015-09-23 13:34:24 -0700156 assert a is not None, "Error parsing json object"
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700157 b = json.dumps( a )
158 return b
Jon Hallfc915882015-07-14 13:33:17 -0700159 else:
160 main.log.error( "Error with REST request, response was: " +
161 str( response ) )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700162 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700163 except ( AttributeError, AssertionError, TypeError ):
164 main.log.exception( self.name + ": Object not as expected" )
Jon Hallfc915882015-07-14 13:33:17 -0700165 return None
Jon Halle401b092015-09-23 13:34:24 -0700166 except Exception:
167 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700168 main.cleanAndExit()
Jon Hallfc915882015-07-14 13:33:17 -0700169
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700170 def intent( self, intentId, appId="org.onosproject.cli",
171 ip="DEFAULT", port="DEFAULT" ):
Jon Hallfc915882015-07-14 13:33:17 -0700172 """
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700173 Description:
174 Get the specific intent information of the given application ID and
175 intent ID
176 Required:
177 str intentId - Intent id in hexadecimal form
178 Optional:
179 str appId - application id of intent
180 Returns:
181 Returns an information dictionary of the given intent;
182 Returns main.FALSE if error on requests; Returns None for exception
183 NOTE:
184 The GET /intents REST api command accepts application id but the
185 api will get updated to accept application name instead
Jon Hallfc915882015-07-14 13:33:17 -0700186 """
187 try:
188 output = None
189 if ip == "DEFAULT":
190 main.log.warn( "No ip given, reverting to ip from topo file" )
191 ip = self.ip_address
192 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -0700193 main.log.warn( "No port given, reverting to port " +
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700194 "from topo file" )
Jon Hallfc915882015-07-14 13:33:17 -0700195 port = self.port
196 # NOTE: REST url requires the intent id to be in decimal form
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700197 query = "/" + str( appId ) + "/" + str( intentId )
suibin zhangd5b6fe42016-05-12 08:48:58 -0700198 response = self.send( url="/intents" + query, ip = ip, port = port )
Jon Hallfc915882015-07-14 13:33:17 -0700199 if response:
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700200 if 200 <= response[ 0 ] <= 299:
201 output = response[ 1 ]
202 a = json.loads( output )
203 return a
Jon Hallfc915882015-07-14 13:33:17 -0700204 else:
205 main.log.error( "Error with REST request, response was: " +
206 str( response ) )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700207 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700208 except ( AttributeError, TypeError ):
209 main.log.exception( self.name + ": Object not as expected" )
Jon Hallfc915882015-07-14 13:33:17 -0700210 return None
Jon Halle401b092015-09-23 13:34:24 -0700211 except Exception:
212 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700213 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700214
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700215 def apps( self, ip="DEFAULT", port="DEFAULT" ):
216 """
217 Description:
218 Returns all the current application installed in the system
219 Returns:
220 List of dictionary of installed application; Returns main.FALSE for
221 error on request; Returns None for exception
222 """
223 try:
224 output = None
225 if ip == "DEFAULT":
226 main.log.warn( "No ip given, reverting to ip from topo file" )
227 ip = self.ip_address
228 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -0700229 main.log.warn( "No port given, reverting to port " +
230 "from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700231 port = self.port
suibin zhangd5b6fe42016-05-12 08:48:58 -0700232 response = self.send( url="/applications", ip = ip, port = port )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700233 if response:
234 if 200 <= response[ 0 ] <= 299:
235 output = response[ 1 ]
236 a = json.loads( output ).get( 'applications' )
Jon Halle401b092015-09-23 13:34:24 -0700237 assert a is not None, "Error parsing json object"
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700238 b = json.dumps( a )
239 return b
240 else:
241 main.log.error( "Error with REST request, response was: " +
242 str( response ) )
243 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700244 except ( AttributeError, AssertionError, TypeError ):
245 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700246 return None
Jon Halle401b092015-09-23 13:34:24 -0700247 except Exception:
248 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700249 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700250
251 def activateApp( self, appName, ip="DEFAULT", port="DEFAULT", check=True ):
252 """
253 Decription:
254 Activate an app that is already installed in ONOS
255 Optional:
256 bool check - If check is True, method will check the status
257 of the app after the command is issued
258 Returns:
259 Returns main.TRUE if the command was successfully or main.FALSE
260 if the REST responded with an error or given incorrect input;
261 Returns None for exception
262
263 """
264 try:
265 output = None
266 if ip == "DEFAULT":
267 main.log.warn( "No ip given, reverting to ip from topo file" )
268 ip = self.ip_address
269 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -0700270 main.log.warn( "No port given, reverting to port " +
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700271 "from topo file" )
272 port = self.port
273 query = "/" + str( appName ) + "/active"
suibin zhang116647a2016-05-06 16:30:09 -0700274 response = self.send( method="POST",
suibin zhangd5b6fe42016-05-12 08:48:58 -0700275 url="/applications" + query,
276 ip = ip, port = port)
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700277 if response:
278 output = response[ 1 ]
279 app = json.loads( output )
280 if 200 <= response[ 0 ] <= 299:
281 if check:
282 if app.get( 'state' ) == 'ACTIVE':
283 main.log.info( self.name + ": " + appName +
284 " application" +
285 " is in ACTIVE state" )
286 return main.TRUE
287 else:
288 main.log.error( self.name + ": " + appName +
289 " application" + " is in " +
290 app.get( 'state' ) + " state" )
291 return main.FALSE
292 else:
293 main.log.warn( "Skipping " + appName +
294 "application check" )
295 return main.TRUE
296 else:
297 main.log.error( "Error with REST request, response was: " +
298 str( response ) )
299 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700300 except ( AttributeError, TypeError ):
301 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700302 return None
Jon Halle401b092015-09-23 13:34:24 -0700303 except Exception:
304 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700305 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700306
307 def deactivateApp( self, appName, ip="DEFAULT", port="DEFAULT",
308 check=True ):
309 """
310 Required:
311 Deactivate an app that is already activated in ONOS
312 Optional:
313 bool check - If check is True, method will check the status of the
314 app after the command is issued
315 Returns:
316 Returns main.TRUE if the command was successfully sent
317 main.FALSE if the REST responded with an error or given
318 incorrect input; Returns None for exception
319 """
320 try:
321 output = None
322 if ip == "DEFAULT":
323 main.log.warn( "No ip given, reverting to ip from topo file" )
324 ip = self.ip_address
325 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -0700326 main.log.warn( "No port given, reverting to port " +
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700327 "from topo file" )
328 port = self.port
329 query = "/" + str( appName ) + "/active"
suibin zhang116647a2016-05-06 16:30:09 -0700330 response = self.send( method="DELETE",
suibin zhangd5b6fe42016-05-12 08:48:58 -0700331 url="/applications" + query,
332 ip = ip, port = port )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700333 if response:
334 output = response[ 1 ]
Jon Hall6040bcf2017-08-14 11:15:41 -0700335 app = {} if output == "" else json.loads( output )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700336 if 200 <= response[ 0 ] <= 299:
337 if check:
338 if app.get( 'state' ) == 'INSTALLED':
339 main.log.info( self.name + ": " + appName +
340 " application" +
341 " is in INSTALLED state" )
342 return main.TRUE
343 else:
344 main.log.error( self.name + ": " + appName +
345 " application" + " is in " +
346 app.get( 'state' ) + " state" )
347 return main.FALSE
348 else:
349 main.log.warn( "Skipping " + appName +
350 "application check" )
351 return main.TRUE
352 else:
353 main.log.error( "Error with REST request, response was: " +
354 str( response ) )
355 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700356 except ( AttributeError, TypeError ):
357 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700358 return None
Jon Halle401b092015-09-23 13:34:24 -0700359 except Exception:
360 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700361 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700362
363 def getApp( self, appName, project="org.onosproject.", ip="DEFAULT",
364 port="DEFAULT" ):
365 """
366 Decription:
367 Gets the informaion of the given application
368 Required:
369 str name - Name of onos application
370 Returns:
371 Returns a dictionary of information ONOS application in string type;
372 Returns main.FALSE if error on requests; Returns None for exception
373 """
374 try:
375 output = None
376 if ip == "DEFAULT":
377 main.log.warn( "No ip given, reverting to ip from topo file" )
378 ip = self.ip_address
379 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -0700380 main.log.warn( "No port given, reverting to port " +
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700381 "from topo file" )
382 port = self.port
383 query = "/" + project + str( appName )
suibin zhangd5b6fe42016-05-12 08:48:58 -0700384 response = self.send( url="/applications" + query,
385 ip = ip, port = port )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700386 if response:
387 if 200 <= response[ 0 ] <= 299:
388 output = response[ 1 ]
389 a = json.loads( output )
390 return a
391 else:
392 main.log.error( "Error with REST request, response was: " +
393 str( response ) )
394 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700395 except ( AttributeError, TypeError ):
396 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700397 return None
Jon Halle401b092015-09-23 13:34:24 -0700398 except Exception:
399 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700400 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700401
402 def addHostIntent( self, hostIdOne, hostIdTwo, appId='org.onosproject.cli',
Jeremy Songsterae2dd452016-05-17 16:44:35 -0700403 ip="DEFAULT", port="DEFAULT", vlanId="" ):
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700404 """
405 Description:
406 Adds a host-to-host intent ( bidirectional ) by
407 specifying the two hosts.
408 Required:
409 * hostIdOne: ONOS host id for host1
410 * hostIdTwo: ONOS host id for host2
411 Optional:
412 str appId - Application name of intent identifier
413 Returns:
kelvin-onlabb50074f2015-07-27 16:18:32 -0700414 Returns main.TRUE for successful requests; Returns main.FALSE if
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700415 error on requests; Returns None for exceptions
416 """
417 try:
418 intentJson = {"two": str( hostIdTwo ),
419 "selector": {"criteria": []}, "priority": 7,
420 "treatment": {"deferred": [], "instructions": []},
421 "appId": appId, "one": str( hostIdOne ),
422 "type": "HostToHostIntent",
423 "constraints": [{"type": "LinkTypeConstraint",
424 "types": ["OPTICAL"],
425 "inclusive": 'false' }]}
Jeremy Songsterae2dd452016-05-17 16:44:35 -0700426 if vlanId:
427 intentJson[ 'selector' ][ 'criteria' ].append( { "type":"VLAN_VID",
428 "vlanId":vlanId } )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700429 output = None
430 if ip == "DEFAULT":
431 main.log.warn( "No ip given, reverting to ip from topo file" )
432 ip = self.ip_address
433 if port == "DEFAULT":
434 main.log.warn( "No port given, reverting to port " +
435 "from topo file" )
436 port = self.port
suibin zhang116647a2016-05-06 16:30:09 -0700437 response = self.send( method="POST",
suibin zhangd5b6fe42016-05-12 08:48:58 -0700438 url="/intents", ip = ip, port = port,
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700439 data=json.dumps( intentJson ) )
440 if response:
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700441 if "201" in str( response[ 0 ] ):
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700442 main.log.info( self.name + ": Successfully POST host" +
443 " intent between host: " + hostIdOne +
444 " and host: " + hostIdTwo )
445 return main.TRUE
446 else:
447 main.log.error( "Error with REST request, response was: " +
448 str( response ) )
449 return main.FALSE
450
Jon Halle401b092015-09-23 13:34:24 -0700451 except ( AttributeError, TypeError ):
452 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700453 return None
Jon Halle401b092015-09-23 13:34:24 -0700454 except Exception:
455 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700456 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700457
kelvin-onlabb50074f2015-07-27 16:18:32 -0700458 def addPointIntent( self,
459 ingressDevice,
460 egressDevice,
kelvin-onlabb50074f2015-07-27 16:18:32 -0700461 appId='org.onosproject.cli',
462 ingressPort="",
463 egressPort="",
464 ethType="",
465 ethSrc="",
466 ethDst="",
467 bandwidth="",
alisonda157272016-12-22 01:13:21 -0800468 protected=False,
kelvin-onlabb50074f2015-07-27 16:18:32 -0700469 lambdaAlloc=False,
470 ipProto="",
471 ipSrc="",
472 ipDst="",
473 tcpSrc="",
kelvin-onlab9b42b0a2015-08-05 14:43:58 -0700474 tcpDst="",
475 ip="DEFAULT",
Jeremy Songsterae2dd452016-05-17 16:44:35 -0700476 port="DEFAULT",
477 vlanId="" ):
kelvin-onlabb50074f2015-07-27 16:18:32 -0700478 """
479 Description:
480 Adds a point-to-point intent ( uni-directional ) by
481 specifying device id's and optional fields
482 Required:
483 * ingressDevice: device id of ingress device
484 * egressDevice: device id of egress device
485 Optional:
486 * ethType: specify ethType
487 * ethSrc: specify ethSrc ( i.e. src mac addr )
488 * ethDst: specify ethDst ( i.e. dst mac addr )
489 * bandwidth: specify bandwidth capacity of link (TODO)
490 * lambdaAlloc: if True, intent will allocate lambda
491 for the specified intent (TODO)
492 * ipProto: specify ip protocol
493 * ipSrc: specify ip source address with mask eg. ip#/24
494 * ipDst: specify ip destination address eg. ip#/24
495 * tcpSrc: specify tcp source port
496 * tcpDst: specify tcp destination port
497 Returns:
498 Returns main.TRUE for successful requests; Returns main.FALSE if
499 no ingress|egress port found and if error on requests;
500 Returns None for exceptions
501 NOTE:
502 The ip and port option are for the requests input's ip and port
503 of the ONOS node
504 """
505 try:
506 if "/" in ingressDevice:
507 if not ingressPort:
508 ingressPort = ingressDevice.split( "/" )[ 1 ]
509 ingressDevice = ingressDevice.split( "/" )[ 0 ]
510 else:
511 if not ingressPort:
512 main.log.debug( self.name + ": Ingress port not specified" )
513 return main.FALSE
514
515 if "/" in egressDevice:
516 if not egressPort:
517 egressPort = egressDevice.split( "/" )[ 1 ]
518 egressDevice = egressDevice.split( "/" )[ 0 ]
519 else:
520 if not egressPort:
521 main.log.debug( self.name + ": Egress port not specified" )
522 return main.FALSE
523
524 intentJson ={ "ingressPoint": { "device": ingressDevice,
525 "port": ingressPort },
526 "selector": { "criteria": [] },
527 "priority": 55,
528 "treatment": { "deferred": [],
529 "instructions": [] },
530 "egressPoint": { "device": egressDevice,
531 "port": egressPort },
532 "appId": appId,
533 "type": "PointToPointIntent",
534 "constraints": [ { "type": "LinkTypeConstraint",
535 "types": [ "OPTICAL" ],
536 "inclusive": "false" } ] }
537
alisonda157272016-12-22 01:13:21 -0800538 # if protected:
539 # intentJson['constraints'].append( { "type": "Protection", "types": ["Protection"], "inclusive": "true" } )
540
kelvin-onlabb50074f2015-07-27 16:18:32 -0700541 if ethType == "IPV4":
542 intentJson[ 'selector' ][ 'criteria' ].append( {
543 "type":"ETH_TYPE",
544 "ethType":2048 } )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -0700545 elif ethType:
546 intentJson[ 'selector' ][ 'criteria' ].append( {
547 "type":"ETH_TYPE",
548 "ethType":ethType } )
549
kelvin-onlabb50074f2015-07-27 16:18:32 -0700550 if ethSrc:
551 intentJson[ 'selector' ][ 'criteria' ].append(
552 { "type":"ETH_SRC",
553 "mac":ethSrc } )
554 if ethDst:
555 intentJson[ 'selector' ][ 'criteria' ].append(
556 { "type":"ETH_DST",
557 "mac":ethDst } )
558 if ipSrc:
559 intentJson[ 'selector' ][ 'criteria' ].append(
560 { "type":"IPV4_SRC",
561 "ip":ipSrc } )
562 if ipDst:
563 intentJson[ 'selector' ][ 'criteria' ].append(
564 { "type":"IPV4_DST",
565 "ip":ipDst } )
566 if tcpSrc:
567 intentJson[ 'selector' ][ 'criteria' ].append(
568 { "type":"TCP_SRC",
569 "tcpPort": tcpSrc } )
570 if tcpDst:
571 intentJson[ 'selector' ][ 'criteria' ].append(
572 { "type":"TCP_DST",
573 "tcpPort": tcpDst } )
574 if ipProto:
575 intentJson[ 'selector' ][ 'criteria' ].append(
576 { "type":"IP_PROTO",
577 "protocol": ipProto } )
Jeremy Songsterae2dd452016-05-17 16:44:35 -0700578 if vlanId:
579 intentJson[ 'selector' ][ 'criteria' ].append(
580 { "type":"VLAN_VID",
581 "vlanId": vlanId } )
kelvin-onlabb50074f2015-07-27 16:18:32 -0700582
583 # TODO: Bandwidth and Lambda will be implemented if needed
584
kelvin-onlabb50074f2015-07-27 16:18:32 -0700585 output = None
586 if ip == "DEFAULT":
587 main.log.warn( "No ip given, reverting to ip from topo file" )
588 ip = self.ip_address
589 if port == "DEFAULT":
590 main.log.warn( "No port given, reverting to port " +
591 "from topo file" )
592 port = self.port
suibin zhang116647a2016-05-06 16:30:09 -0700593 response = self.send( method="POST",
suibin zhangd5b6fe42016-05-12 08:48:58 -0700594 url="/intents", ip = ip, port = port,
kelvin-onlabb50074f2015-07-27 16:18:32 -0700595 data=json.dumps( intentJson ) )
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700596
597 main.log.debug( intentJson )
598
kelvin-onlabb50074f2015-07-27 16:18:32 -0700599 if response:
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700600 if "201" in str( response[ 0 ] ):
kelvin-onlabb50074f2015-07-27 16:18:32 -0700601 main.log.info( self.name + ": Successfully POST point" +
602 " intent between ingress: " + ingressDevice +
603 " and egress: " + egressDevice + " devices" )
604 return main.TRUE
605 else:
606 main.log.error( "Error with REST request, response was: " +
607 str( response ) )
608 return main.FALSE
609
Jon Halle401b092015-09-23 13:34:24 -0700610 except ( AttributeError, TypeError ):
611 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlabb50074f2015-07-27 16:18:32 -0700612 return None
Jon Halle401b092015-09-23 13:34:24 -0700613 except Exception:
614 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700615 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700616
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700617 def addSinglepointToMultipointIntent(self,
618 ingressDevice,
619 egressDeviceList,
620 portEgressList,
621 appId='org.onosproject.cli',
622 portIngress="",
623 ethType="",
624 ethSrc="",
625 ethDst="",
626 bandwidth="",
627 lambdaAlloc=False,
628 ipProto="",
629 ipSrc="",
630 ipDst="",
631 tcpSrc="",
632 tcpDst="",
633 partial=False,
634 ip="DEFAULT",
635 port="DEFAULT",
636 vlanId="" ):
637 """
638 Description:
639 Adds a point-to-multi point intent ( uni-directional ) by
640 specifying device id's and optional fields
641 Required:
642 * ingressDevice: device id of ingress device
643 * egressDevice: device id of egress device
644 * portEgressList: a list of port id of egress device
645
646 Optional:
647 * portIngress: port id of ingress device
648 * ethType: specify ethType
649 * ethSrc: specify ethSrc ( i.e. src mac addr )
650 * ethDst: specify ethDst ( i.e. dst mac addr )
651 * bandwidth: specify bandwidth capacity of link (TODO)
652 * lambdaAlloc: if True, intent will allocate lambda
653 for the specified intent (TODO)
654 * ipProto: specify ip protocol
655 * ipSrc: specify ip source address with mask eg. ip#/24
656 * ipDst: specify ip destination address eg. ip#/24
657 * tcpSrc: specify tcp source port
658 * tcpDst: specify tcp destination port
659 Returns:
660 Returns main.TRUE for successful requests; Returns main.FALSE if
661 no ingress|egress port found and if error on requests;
662 Returns None for exceptions
663 NOTE:
664 The ip and port option are for the requests input's ip and port
665 of the ONOS node
666 """
667 try:
668
669 if "/" in ingressDevice:
670 if not portIngress:
671 ingressPort = ingressDevice.split( "/" )[ 1 ]
672 ingressDevice = ingressDevice.split( "/" )[ 0 ]
673 else:
674 if not portIngress:
675 main.log.debug( self.name + ": Ingress port not specified" )
676 return main.FALSE
677 index = 0
678 for egressDevice in egressDeviceList:
679 if "/" in egressDevice:
680 portEgressList.append( egressDevice.split( "/" )[ 1 ] )
681 egressDeviceList[ index ] = egressDevice.split( "/" )[ 0 ]
682 else:
683 if not portEgressList:
684 main.log.debug( self.name + ": Egress port not specified" )
685 return main.FALSE
686 index = index + 1
687
688 intentJson = { "ingressPoint": { "device": ingressDevice,
689 "port": ingressPort },
690 "selector": { "criteria": [] },
691 "priority": 55,
692 "treatment": { "deferred": [],
693 "instructions": [] },
694 "egressPoint": { "connectPoints": [] },
695 "appId": appId,
696 "type": "SinglePointToMultiPointIntent",
697 "constraints": [ { "type": "LinkTypeConstraint",
698 "types": ["OPTICAL"],
699 "inclusive": "false" } ] }
700
701 index = 0
702 for ep in portEgressList:
703 intentJson[ 'egressPoint' ][ 'connectPoints' ].append(
704 { "device": egressDeviceList[ index ],
705 "port": ep } )
706 index += 1
707
708 if ethType == "IPV4":
709 intentJson[ 'selector' ][ 'criteria' ].append(
710 { "type": "ETH_TYPE",
711 "ethType": 2048 } )
712 elif ethType:
713 intentJson[ 'selector' ][ 'criteria' ].append(
714 { "type": "ETH_TYPE",
715 "ethType": ethType } )
716
717 if ethSrc:
718 intentJson[ 'selector' ][ 'criteria' ].append(
719 { "type": "ETH_SRC",
720 "mac": ethSrc } )
721
722 if ethDst:
723 for dst in ethDst:
724 if dst:
725 intentJson[ 'selector' ][ 'criteria' ].append(
726 { "type": "ETH_DST",
727 "mac": dst } )
728 if tcpSrc:
729 intentJson[ 'selector' ][ 'criteria' ].append(
730 { "type": "TCP_SRC",
731 "tcpPort": tcpSrc } )
732 if tcpDst:
733 intentJson[ 'selector' ][ 'criteria' ].append(
734 { "type": "TCP_DST",
735 "tcpPort": tcpDst } )
736 if ipProto:
737 intentJson[ 'selector' ][ 'criteria' ].append(
738 { "type": "IP_PROTO",
739 "protocol": ipProto } )
740 if vlanId:
741 intentJson[ 'selector' ][ 'criteria' ].append(
742 { "type": "VLAN_VID",
743 "vlanId": vlanId } )
744
745 # TODO: Bandwidth and Lambda will be implemented if needed
746
747 output = None
748 if ip == "DEFAULT":
749 main.log.warn( "No ip given, reverting to ip from topo file" )
750 ip = self.ip_address
751 if port == "DEFAULT":
752 main.log.warn( "No port given, reverting to port " +
753 "from topo file" )
754 port = self.port
755 response = self.send( method="POST",
756 url="/intents", ip=ip, port=port,
757 data=json.dumps( intentJson ) )
758
759 main.log.debug(intentJson)
760
761 if response:
762 if "201" in str( response[ 0 ] ):
763 main.log.info( self.name + ": Successfully POST point" +
764 " intent between ingress: " + ingressDevice +
765 " and egress: " + str(egressDeviceList) + " devices" )
766 return main.TRUE
767 else:
768 main.log.error( "Error with REST request, response was: " + str( response ) )
769 return main.FALSE
770 else:
771 main.log.error( "REST request has no response." )
772 return main.FALSE
773
774 except ( AttributeError, TypeError ):
775 main.log.exception( self.name + ": Object not as expected" )
776 return None
777 except Exception:
778 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700779 main.cleanAndExit()
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700780
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700781 def removeIntent( self, intentId, appId='org.onosproject.cli',
782 ip="DEFAULT", port="DEFAULT" ):
783 """
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700784 Remove intent for specified application id and intent id;
785 Returns None for exception
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700786 """
787 try:
788 output = None
789 if ip == "DEFAULT":
790 main.log.warn( "No ip given, reverting to ip from topo file" )
791 ip = self.ip_address
792 if port == "DEFAULT":
793 main.log.warn( "No port given, reverting to port " +
794 "from topo file" )
795 port = self.port
796 # NOTE: REST url requires the intent id to be in decimal form
797 query = "/" + str( appId ) + "/" + str( int( intentId, 16 ) )
suibin zhang116647a2016-05-06 16:30:09 -0700798 response = self.send( method="DELETE",
suibin zhangd5b6fe42016-05-12 08:48:58 -0700799 url="/intents" + query, ip = ip, port = port )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700800 if response:
801 if 200 <= response[ 0 ] <= 299:
802 return main.TRUE
803 else:
804 main.log.error( "Error with REST request, response was: " +
805 str( response ) )
806 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700807 except ( AttributeError, TypeError ):
808 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700809 return None
Jon Halle401b092015-09-23 13:34:24 -0700810 except Exception:
811 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700812 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700813
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700814 def getIntentsId( self ):
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700815 """
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700816 Description:
817 Gets all intents ID using intents function
818 Returns:
819 List of intents ID if found any intents; Returns main.FALSE for other exceptions
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700820 """
821 try:
822 intentIdList = []
823 intentsJson = json.loads( self.intents() )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700824 for intent in intentsJson:
825 intentIdList.append( intent.get( 'id' ) )
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700826 if not intentIdList:
827 main.log.debug( "Cannot find any intents" )
828 return main.FALSE
829 else:
830 return intentIdList
Jon Halle401b092015-09-23 13:34:24 -0700831 except ( AttributeError, TypeError ):
832 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700833 return None
Jon Halle401b092015-09-23 13:34:24 -0700834 except Exception:
835 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700836 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700837
838 def removeAllIntents( self, intentIdList ='ALL',appId='org.onosproject.cli',
839 ip="DEFAULT", port="DEFAULT", delay=5 ):
840 """
841 Description:
842 Remove all the intents
843 Returns:
844 Returns main.TRUE if all intents are removed, otherwise returns
845 main.FALSE; Returns None for exception
846 """
847 try:
848 results = []
849 if intentIdList == 'ALL':
Ming Yan Shuab2f7f52016-08-03 15:21:24 -0700850 # intentIdList = self.getIntentsId( ip=ip, port=port )
851 intentIdList = self.getIntentsId()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700852
853 main.log.info( self.name + ": Removing intents " +
854 str( intentIdList ) )
855
856 if isinstance( intentIdList, types.ListType ):
857 for intent in intentIdList:
858 results.append( self.removeIntent( intentId=intent,
859 appId=appId,
860 ip=ip,
861 port=port ) )
862 # Check for remaining intents
863 # NOTE: Noticing some delay on Deleting the intents so i put
864 # this time out
865 import time
866 time.sleep( delay )
867 intentRemain = len( json.loads( self.intents() ) )
868 if all( result==main.TRUE for result in results ) and \
869 intentRemain == 0:
870 main.log.info( self.name + ": All intents are removed " )
871 return main.TRUE
872 else:
873 main.log.error( self.name + ": Did not removed all intents,"
874 + " there are " + str( intentRemain )
875 + " intents remaining" )
876 return main.FALSE
877 else:
878 main.log.debug( self.name + ": There is no intents ID list" )
Jon Halle401b092015-09-23 13:34:24 -0700879 except ( AttributeError, TypeError ):
880 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700881 return None
Jon Halle401b092015-09-23 13:34:24 -0700882 except Exception:
883 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700884 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700885
886 def hosts( self, ip="DEFAULT", port="DEFAULT" ):
887 """
888 Description:
889 Get a list of dictionary of all discovered hosts
890 Returns:
891 Returns a list of dictionary of information of the hosts currently
892 discovered by ONOS; Returns main.FALSE if error on requests;
893 Returns None for exception
894 """
895 try:
896 output = None
897 if ip == "DEFAULT":
898 main.log.warn( "No ip given, reverting to ip from topo file" )
899 ip = self.ip_address
900 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -0700901 main.log.warn( "No port given, reverting to port " +
902 "from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700903 port = self.port
suibin zhangd5b6fe42016-05-12 08:48:58 -0700904 response = self.send( url="/hosts", ip = ip, port = port )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700905 if response:
906 if 200 <= response[ 0 ] <= 299:
907 output = response[ 1 ]
908 a = json.loads( output ).get( 'hosts' )
Jon Halle401b092015-09-23 13:34:24 -0700909 assert a is not None, "Error parsing json object"
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700910 b = json.dumps( a )
911 return b
912 else:
913 main.log.error( "Error with REST request, response was: " +
914 str( response ) )
915 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700916 except ( AttributeError, AssertionError, TypeError ):
917 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700918 return None
Jon Halle401b092015-09-23 13:34:24 -0700919 except Exception:
920 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700921 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700922
923 def getHost( self, mac, vlan="-1", ip="DEFAULT", port="DEFAULT" ):
924 """
925 Description:
926 Gets the information from the given host
927 Required:
928 str mac - MAC address of the host
929 Optional:
930 str vlan - VLAN tag of the host, defaults to -1
931 Returns:
932 Return the host id from the hosts/mac/vlan output in REST api
933 whose 'id' contains mac/vlan; Returns None for exception;
934 Returns main.FALSE if error on requests
935
936 NOTE:
937 Not sure what this function should do, any suggestion?
938 """
939 try:
940 output = None
941 if ip == "DEFAULT":
942 main.log.warn( "No ip given, reverting to ip from topo file" )
943 ip = self.ip_address
944 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -0700945 main.log.warn( "No port given, reverting to port " +
946 "from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700947 port = self.port
948 query = "/" + mac + "/" + vlan
suibin zhangd5b6fe42016-05-12 08:48:58 -0700949 response = self.send( url="/hosts" + query, ip = ip, port = port )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700950 if response:
951 # NOTE: What if the person wants other values? would it be better
952 # to have a function that gets a key and return a value instead?
953 # This function requires mac and vlan and returns an ID which
954 # makes this current function useless
955 if 200 <= response[ 0 ] <= 299:
956 output = response[ 1 ]
957 hostId = json.loads( output ).get( 'id' )
958 return hostId
959 else:
960 main.log.error( "Error with REST request, response was: " +
961 str( response ) )
962 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700963 except ( AttributeError, TypeError ):
964 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700965 return None
Jon Halle401b092015-09-23 13:34:24 -0700966 except Exception:
967 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -0700968 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700969
970 def topology( self, ip="DEFAULT", port="DEFAULT" ):
971 """
972 Description:
973 Gets the overview of network topology
974 Returns:
975 Returns a dictionary containing information about network topology;
976 Returns None for exception
977 """
978 try:
979 output = None
980 if ip == "DEFAULT":
981 main.log.warn( "No ip given, reverting to ip from topo file" )
982 ip = self.ip_address
983 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -0700984 main.log.warn( "No port given, reverting to port " +
985 "from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700986 port = self.port
suibin zhangd5b6fe42016-05-12 08:48:58 -0700987 response = self.send( url="/topology", ip = ip, port = port )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700988 if response:
989 if 200 <= response[ 0 ] <= 299:
990 output = response[ 1 ]
991 a = json.loads( output )
992 b = json.dumps( a )
993 return b
994 else:
995 main.log.error( "Error with REST request, response was: " +
996 str( response ) )
997 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700998 except ( AttributeError, TypeError ):
999 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001000 return None
Jon Halle401b092015-09-23 13:34:24 -07001001 except Exception:
1002 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001003 main.cleanAndExit()
Jon Halle401b092015-09-23 13:34:24 -07001004
1005 def devices( self, ip="DEFAULT", port="DEFAULT" ):
1006 """
1007 Description:
1008 Get the devices discovered by ONOS is json string format
1009 Returns:
1010 a json string of the devices currently discovered by ONOS OR
1011 main.FALSE if there is an error in the request OR
1012 Returns None for exception
1013 """
1014 try:
1015 output = None
1016 if ip == "DEFAULT":
1017 main.log.warn( "No ip given, reverting to ip from topo file" )
1018 ip = self.ip_address
1019 if port == "DEFAULT":
1020 main.log.warn( "No port given, reverting to port " +
1021 "from topo file" )
1022 port = self.port
suibin zhangd5b6fe42016-05-12 08:48:58 -07001023 response = self.send( url="/devices", ip = ip, port = port )
Jon Halle401b092015-09-23 13:34:24 -07001024 if response:
1025 if 200 <= response[ 0 ] <= 299:
1026 output = response[ 1 ]
1027 a = json.loads( output ).get( 'devices' )
1028 assert a is not None, "Error parsing json object"
1029 b = json.dumps( a )
1030 return b
1031 else:
1032 main.log.error( "Error with REST request, response was: " +
1033 str( response ) )
1034 return main.FALSE
1035 except ( AttributeError, AssertionError, TypeError ):
1036 main.log.exception( self.name + ": Object not as expected" )
1037 return None
1038 except Exception:
1039 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001040 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001041
1042 def getIntentState( self, intentsId, intentsJson=None,
1043 ip="DEFAULT", port="DEFAULT" ):
1044 """
1045 Description:
1046 Get intent state.
1047 Accepts a single intent ID (string type) or a list of intent IDs.
1048 Returns the state(string type) of the id if a single intent ID is
1049 accepted.
1050 Required:
1051 intentId: intent ID (string type)
1052 intentsJson: parsed json object from the onos:intents api
1053 Returns:
1054 Returns a dictionary with intent IDs as the key and its
1055 corresponding states as the values; Returns None for invalid IDs or
1056 Type error and any exceptions
1057 NOTE:
1058 An intent's state consist of INSTALLED,WITHDRAWN etc.
1059 """
1060 try:
1061 state = "State is Undefined"
1062 if not intentsJson:
1063 intentsJsonTemp = json.loads( self.intents() )
1064 else:
1065 intentsJsonTemp = json.loads( intentsJson )
1066 if isinstance( intentsId, types.StringType ):
1067 for intent in intentsJsonTemp:
1068 if intentsId == intent[ 'id' ]:
1069 state = intent[ 'state' ]
1070 return state
1071 main.log.info( "Cannot find intent ID" + str( intentsId ) +
1072 " on the list" )
1073 return state
1074 elif isinstance( intentsId, types.ListType ):
1075 dictList = []
1076 for i in xrange( len( intentsId ) ):
1077 stateDict = {}
1078 for intents in intentsJsonTemp:
1079 if intentsId[ i ] == intents[ 'id' ]:
1080 stateDict[ 'state' ] = intents[ 'state' ]
1081 stateDict[ 'id' ] = intentsId[ i ]
1082 dictList.append( stateDict )
1083 break
1084 if len( intentsId ) != len( dictList ):
1085 main.log.info( "Cannot find some of the intent ID state" )
1086 return dictList
1087 else:
1088 main.log.info( "Invalid intents ID entry" )
1089 return None
1090
Jon Halle401b092015-09-23 13:34:24 -07001091 except ( AttributeError, TypeError ):
1092 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001093 return None
Jon Halle401b092015-09-23 13:34:24 -07001094 except Exception:
1095 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001096 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001097
1098 def checkIntentState( self, intentsId="ALL", expectedState='INSTALLED',
1099 ip="DEFAULT", port="DEFAULT"):
1100 """
1101 Description:
1102 Check intents state based on expected state which defaults to
1103 INSTALLED state
1104 Required:
1105 intentsId - List of intents ID to be checked
1106 Optional:
1107 expectedState - Check the expected state(s) of each intents
1108 state in the list.
1109 *NOTE: You can pass in a list of expected state,
1110 Eg: expectedState = [ 'INSTALLED' , 'INSTALLING' ]
1111 Return:
1112 Returns main.TRUE only if all intent are the same as expected states
1113 , otherwise, returns main.FALSE; Returns None for general exception
1114 """
1115 try:
1116 # Generating a dictionary: intent id as a key and state as value
1117 returnValue = main.TRUE
1118 if intentsId == "ALL":
1119 intentsId = self.getIntentsId( ip=ip, port=port )
1120 intentsDict = self.getIntentState( intentsId, ip=ip, port=port )
1121
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001122 if len( intentsId ) != len( intentsDict ):
1123 main.log.error( self.name + ": There is something wrong " +
1124 "getting intents state" )
1125 return main.FALSE
1126
1127 if isinstance( expectedState, types.StringType ):
1128 for intents in intentsDict:
1129 if intents.get( 'state' ) != expectedState:
1130 main.log.debug( self.name + " : Intent ID - " +
1131 intents.get( 'id' ) +
1132 " actual state = " +
1133 intents.get( 'state' )
1134 + " does not equal expected state = "
1135 + expectedState )
1136 returnValue = main.FALSE
1137
1138 elif isinstance( expectedState, types.ListType ):
1139 for intents in intentsDict:
1140 if not any( state == intents.get( 'state' ) for state in
1141 expectedState ):
1142 main.log.debug( self.name + " : Intent ID - " +
1143 intents.get( 'id' ) +
1144 " actual state = " +
1145 intents.get( 'state' ) +
1146 " does not equal expected states = "
1147 + str( expectedState ) )
1148 returnValue = main.FALSE
1149
1150 if returnValue == main.TRUE:
1151 main.log.info( self.name + ": All " +
1152 str( len( intentsDict ) ) +
1153 " intents are in " + str( expectedState ) +
1154 " state" )
1155 return returnValue
Jon Halle401b092015-09-23 13:34:24 -07001156 except ( AttributeError, TypeError ):
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001157 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001158 return None
Jon Halle401b092015-09-23 13:34:24 -07001159 except Exception:
1160 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001161 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001162
Jeremy Songster306ed7a2016-07-19 10:59:07 -07001163 def flows( self, ip="DEFAULT", port="DEFAULT", subjectClass=None, subjectKey=None ):
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001164 """
1165 Description:
1166 Get flows currently added to the system
1167 NOTE:
1168 The flows -j cli command has completely different format than
Jon Halle401b092015-09-23 13:34:24 -07001169 the REST output
1170
1171 Returns None for exception
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001172 """
1173 try:
1174 output = None
Jeremy Songster306ed7a2016-07-19 10:59:07 -07001175 url = "/flows"
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001176 if ip == "DEFAULT":
1177 main.log.warn( "No ip given, reverting to ip from topo file" )
1178 ip = self.ip_address
1179 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -07001180 main.log.warn( "No port given, reverting to port " +
1181 "from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001182 port = self.port
Jeremy Songster306ed7a2016-07-19 10:59:07 -07001183 if subjectKey and not subjectClass:
1184 main.log.warning( "Subject Key provided without Subject Class. Ignoring Subject Key" )
1185 if subjectClass:
1186 url += "/" + subjectClass
1187 if subjectKey:
1188 url += "/" + subjectKey
1189 response = self.send( url=url, ip=ip, port=port )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001190 if response:
1191 if 200 <= response[ 0 ] <= 299:
1192 output = response[ 1 ]
1193 a = json.loads( output ).get( 'flows' )
Jon Halle401b092015-09-23 13:34:24 -07001194 assert a is not None, "Error parsing json object"
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001195 b = json.dumps( a )
1196 return b
1197 else:
1198 main.log.error( "Error with REST request, response was: " +
1199 str( response ) )
1200 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -07001201 except ( AttributeError, AssertionError, TypeError ):
1202 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001203 return None
Jon Halle401b092015-09-23 13:34:24 -07001204 except Exception:
1205 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001206 main.cleanAndExit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001207
Jon Halle401b092015-09-23 13:34:24 -07001208 def getFlows( self, deviceId, flowId=None, ip="DEFAULT", port="DEFAULT" ):
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001209 """
1210 Description:
1211 Gets all the flows of the device or get a specific flow in the
1212 device by giving its flow ID
1213 Required:
Jon Halle401b092015-09-23 13:34:24 -07001214 str deviceId - device/switch Id
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001215 Optional:
1216 int/hex flowId - ID of the flow
1217 """
1218 try:
1219 output = None
1220 if ip == "DEFAULT":
1221 main.log.warn( "No ip given, reverting to ip from topo file" )
1222 ip = self.ip_address
1223 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -07001224 main.log.warn( "No port given, reverting to port " +
1225 "from topo file" )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001226 port = self.port
Jon Halle401b092015-09-23 13:34:24 -07001227 url = "/flows/" + deviceId
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001228 if flowId:
1229 url += "/" + str( int( flowId ) )
1230 print url
suibin zhangd5b6fe42016-05-12 08:48:58 -07001231 response = self.send( url=url, ip = ip, port = port )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001232 if response:
1233 if 200 <= response[ 0 ] <= 299:
1234 output = response[ 1 ]
1235 a = json.loads( output ).get( 'flows' )
Jon Halle401b092015-09-23 13:34:24 -07001236 assert a is not None, "Error parsing json object"
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001237 b = json.dumps( a )
1238 return b
1239 else:
1240 main.log.error( "Error with REST request, response was: " +
1241 str( response ) )
1242 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -07001243 except ( AttributeError, AssertionError, TypeError ):
1244 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001245 return None
Jon Halle401b092015-09-23 13:34:24 -07001246 except Exception:
1247 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001248 main.cleanAndExit()
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001249
GlennRC073e8bc2015-10-27 17:11:28 -07001250 def sendFlow( self, deviceId, flowJson, ip="DEFAULT", port="DEFAULT", debug=False ):
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001251 """
1252 Description:
GlennRC073e8bc2015-10-27 17:11:28 -07001253 Sends a single flow to the specified device. This function exists
1254 so you can bypass the addFLow driver and send your own custom flow.
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001255 Required:
GlennRC073e8bc2015-10-27 17:11:28 -07001256 * The flow in json
1257 * the device id to add the flow to
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001258 Returns:
1259 Returns main.TRUE for successful requests; Returns main.FALSE
1260 if error on requests;
1261 Returns None for exceptions
1262 NOTE:
1263 The ip and port option are for the requests input's ip and port
1264 of the ONOS node
1265 """
GlennRC073e8bc2015-10-27 17:11:28 -07001266
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001267 try:
GlennRC073e8bc2015-10-27 17:11:28 -07001268 if debug: main.log.debug( "Adding flow: " + self.pprint( flowJson ) )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001269 output = None
1270 if ip == "DEFAULT":
1271 main.log.warn( "No ip given, reverting to ip from topo file" )
1272 ip = self.ip_address
1273 if port == "DEFAULT":
1274 main.log.warn( "No port given, reverting to port " +
1275 "from topo file" )
1276 port = self.port
1277 url = "/flows/" + deviceId
suibin zhang116647a2016-05-06 16:30:09 -07001278 response = self.send( method="POST",
suibin zhangd5b6fe42016-05-12 08:48:58 -07001279 url=url, ip = ip, port = port,
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001280 data=json.dumps( flowJson ) )
1281 if response:
Ming Yan Shuab2f7f52016-08-03 15:21:24 -07001282 if "201" in str( response[ 0 ] ):
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001283 main.log.info( self.name + ": Successfully POST flow" +
1284 "in device: " + str( deviceId ) )
1285 return main.TRUE
1286 else:
1287 main.log.error( "Error with REST request, response was: " +
1288 str( response ) )
1289 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -07001290 except NotImplementedError as e:
1291 raise e # Inform the caller
1292 except ( AttributeError, TypeError ):
1293 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001294 return None
Jon Halle401b092015-09-23 13:34:24 -07001295 except Exception:
1296 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001297 main.cleanAndExit()
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001298
GlennRC073e8bc2015-10-27 17:11:28 -07001299 def addFlow( self,
1300 deviceId,
1301 appId=0,
1302 ingressPort="",
1303 egressPort="",
1304 ethType="",
1305 ethSrc="",
1306 ethDst="",
1307 vlan="",
1308 ipProto="",
1309 ipSrc=(),
1310 ipDst=(),
1311 tcpSrc="",
1312 tcpDst="",
GlennRC956ea742015-11-05 16:14:15 -08001313 udpDst="",
1314 udpSrc="",
1315 mpls="",
alisone14d7b02016-07-06 10:31:51 -07001316 priority=100,
kavitha Alagesan373e0552016-11-22 05:22:05 +05301317 groupId="",
GlennRC073e8bc2015-10-27 17:11:28 -07001318 ip="DEFAULT",
1319 port="DEFAULT",
1320 debug=False ):
1321 """
1322 Description:
1323 Creates a single flow in the specified device
1324 Required:
1325 * deviceId: id of the device
1326 Optional:
1327 * ingressPort: port ingress device
1328 * egressPort: port of egress device
1329 * ethType: specify ethType
1330 * ethSrc: specify ethSrc ( i.e. src mac addr )
1331 * ethDst: specify ethDst ( i.e. dst mac addr )
1332 * ipProto: specify ip protocol
1333 * ipSrc: specify ip source address with mask eg. ip#/24
1334 as a tuple (type, ip#)
1335 * ipDst: specify ip destination address eg. ip#/24
1336 as a tuple (type, ip#)
1337 * tcpSrc: specify tcp source port
1338 * tcpDst: specify tcp destination port
1339 Returns:
1340 Returns main.TRUE for successful requests; Returns main.FALSE
1341 if error on requests;
1342 Returns None for exceptions
1343 NOTE:
1344 The ip and port option are for the requests input's ip and port
1345 of the ONOS node
1346 """
1347 try:
alisone14d7b02016-07-06 10:31:51 -07001348 flowJson = { "priority":priority,
GlennRC073e8bc2015-10-27 17:11:28 -07001349 "isPermanent":"true",
1350 "timeout":0,
1351 "deviceId":deviceId,
1352 "treatment":{"instructions":[]},
1353 "selector": {"criteria":[]}}
1354 if appId:
1355 flowJson[ "appId" ] = appId
kavitha Alagesan373e0552016-11-22 05:22:05 +05301356
1357 if groupId:
1358 flowJson[ 'treatment' ][ 'instructions' ].append( {
1359 "type":"GROUP",
1360 "groupId":groupId } )
1361
GlennRC073e8bc2015-10-27 17:11:28 -07001362 if egressPort:
1363 flowJson[ 'treatment' ][ 'instructions' ].append( {
1364 "type":"OUTPUT",
1365 "port":egressPort } )
1366 if ingressPort:
1367 flowJson[ 'selector' ][ 'criteria' ].append( {
1368 "type":"IN_PORT",
1369 "port":ingressPort } )
1370 if ethType:
1371 flowJson[ 'selector' ][ 'criteria' ].append( {
1372 "type":"ETH_TYPE",
1373 "ethType":ethType } )
1374 if ethSrc:
1375 flowJson[ 'selector' ][ 'criteria' ].append( {
1376 "type":"ETH_SRC",
1377 "mac":ethSrc } )
1378 if ethDst:
1379 flowJson[ 'selector' ][ 'criteria' ].append( {
1380 "type":"ETH_DST",
1381 "mac":ethDst } )
1382 if vlan:
1383 flowJson[ 'selector' ][ 'criteria' ].append( {
1384 "type":"VLAN_VID",
1385 "vlanId":vlan } )
GlennRC956ea742015-11-05 16:14:15 -08001386 if mpls:
1387 flowJson[ 'selector' ][ 'criteria' ].append( {
1388 "type":"MPLS_LABEL",
1389 "label":mpls } )
GlennRC073e8bc2015-10-27 17:11:28 -07001390 if ipSrc:
1391 flowJson[ 'selector' ][ 'criteria' ].append( {
1392 "type":ipSrc[0],
1393 "ip":ipSrc[1] } )
1394 if ipDst:
1395 flowJson[ 'selector' ][ 'criteria' ].append( {
1396 "type":ipDst[0],
1397 "ip":ipDst[1] } )
1398 if tcpSrc:
1399 flowJson[ 'selector' ][ 'criteria' ].append( {
1400 "type":"TCP_SRC",
1401 "tcpPort": tcpSrc } )
1402 if tcpDst:
1403 flowJson[ 'selector' ][ 'criteria' ].append( {
1404 "type":"TCP_DST",
1405 "tcpPort": tcpDst } )
GlennRC956ea742015-11-05 16:14:15 -08001406 if udpSrc:
1407 flowJson[ 'selector' ][ 'criteria' ].append( {
1408 "type":"UDP_SRC",
1409 "udpPort": udpSrc } )
1410 if udpDst:
1411 flowJson[ 'selector' ][ 'criteria' ].append( {
1412 "type":"UDP_DST",
1413 "udpPort": udpDst } )
GlennRC073e8bc2015-10-27 17:11:28 -07001414 if ipProto:
1415 flowJson[ 'selector' ][ 'criteria' ].append( {
1416 "type":"IP_PROTO",
1417 "protocol": ipProto } )
1418
1419 return self.sendFlow( deviceId=deviceId, flowJson=flowJson, debug=debug )
1420
1421 except ( AttributeError, TypeError ):
1422 main.log.exception( self.name + ": Object not as expected" )
1423 return None
1424 except Exception:
1425 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001426 main.cleanAndExit()
GlennRC073e8bc2015-10-27 17:11:28 -07001427
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001428 def removeFlow( self, deviceId, flowId,
1429 ip="DEFAULT", port="DEFAULT" ):
1430 """
1431 Description:
1432 Remove specific device flow
1433 Required:
1434 str deviceId - id of the device
1435 str flowId - id of the flow
1436 Return:
1437 Returns main.TRUE if successfully deletes flows, otherwise
1438 Returns main.FALSE, Returns None on error
1439 """
1440 try:
1441 output = None
1442 if ip == "DEFAULT":
1443 main.log.warn( "No ip given, reverting to ip from topo file" )
1444 ip = self.ip_address
1445 if port == "DEFAULT":
1446 main.log.warn( "No port given, reverting to port " +
1447 "from topo file" )
1448 port = self.port
1449 # NOTE: REST url requires the intent id to be in decimal form
1450 query = "/" + str( deviceId ) + "/" + str( int( flowId ) )
suibin zhang116647a2016-05-06 16:30:09 -07001451 response = self.send( method="DELETE",
suibin zhangd5b6fe42016-05-12 08:48:58 -07001452 url="/flows" + query, ip = ip, port = port )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001453 if response:
1454 if 200 <= response[ 0 ] <= 299:
1455 return main.TRUE
1456 else:
1457 main.log.error( "Error with REST request, response was: " +
1458 str( response ) )
1459 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -07001460 except ( AttributeError, TypeError ):
1461 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001462 return None
Jon Halle401b092015-09-23 13:34:24 -07001463 except Exception:
1464 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001465 main.cleanAndExit()
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001466
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001467 def checkFlowsState( self , ip="DEFAULT", port="DEFAULT" ):
1468 """
1469 Description:
1470 Check if all the current flows are in ADDED state
1471 Return:
1472 returnValue - Returns main.TRUE only if all flows are in
1473 return main.FALSE otherwise;
1474 Returns None for exception
1475 """
1476 try:
1477 tempFlows = json.loads( self.flows( ip=ip, port=port ) )
1478 returnValue = main.TRUE
1479 for flow in tempFlows:
1480 if flow.get( 'state' ) != 'ADDED':
1481 main.log.info( self.name + ": flow Id: " +
1482 str( flow.get( 'groupId' ) ) +
1483 " | state:" +
1484 str( flow.get( 'state' ) ) )
1485 returnValue = main.FALSE
1486 return returnValue
Jon Halle401b092015-09-23 13:34:24 -07001487 except ( AttributeError, TypeError ):
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001488 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001489 return None
1490 except Exception:
1491 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001492 main.cleanAndExit()
Jon Hall66e001c2015-11-12 09:45:10 -08001493
1494 def getNetCfg( self, ip="DEFAULT", port="DEFAULT",
1495 subjectClass=None, subjectKey=None, configKey=None ):
1496 """
1497 Description:
1498 Get a json object with the ONOS network configurations
1499 Returns:
1500 A json object containing the network configuration in
1501 ONOS; Returns main.FALSE if error on requests;
1502 Returns None for exception
1503 """
1504 try:
1505 output = None
1506 if ip == "DEFAULT":
1507 main.log.warn( "No ip given, reverting to ip from topo file" )
1508 ip = self.ip_address
1509 if port == "DEFAULT":
1510 main.log.warn( "No port given, reverting to port " +
1511 "from topo file" )
1512 port = self.port
1513 url = "/network/configuration"
1514 if subjectClass:
1515 url += "/" + subjectClass
1516 if subjectKey:
1517 url += "/" + subjectKey
1518 if configKey:
1519 url += "/" + configKey
suibin zhangd5b6fe42016-05-12 08:48:58 -07001520 response = self.send( url=url, ip = ip, port = port )
Jon Hall66e001c2015-11-12 09:45:10 -08001521 if response:
1522 if 200 <= response[ 0 ] <= 299:
1523 output = response[ 1 ]
1524 a = json.loads( output )
1525 b = json.dumps( a )
1526 return b
1527 elif response[ 0 ] == 404:
1528 main.log.error( "Requested configuration doesn't exist: " +
1529 str( response ) )
1530 return {}
1531 else:
1532 main.log.error( "Error with REST request, response was: " +
1533 str( response ) )
1534 return main.FALSE
1535 except ( AttributeError, TypeError ):
1536 main.log.exception( self.name + ": Object not as expected" )
1537 return None
1538 except Exception:
1539 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001540 main.cleanAndExit()
Jon Hall66e001c2015-11-12 09:45:10 -08001541
1542 def setNetCfg( self, cfgJson, ip="DEFAULT", port="DEFAULT",
1543 subjectClass=None, subjectKey=None, configKey=None ):
1544 """
1545 Description:
1546 Set a json object with the ONOS network configurations
1547 Returns:
1548 Returns main.TRUE for successful requests; Returns main.FALSE
1549 if error on requests;
1550 Returns None for exceptions
1551
1552 """
1553 try:
1554 output = None
1555 if ip == "DEFAULT":
1556 main.log.warn( "No ip given, reverting to ip from topo file" )
1557 ip = self.ip_address
1558 if port == "DEFAULT":
1559 main.log.warn( "No port given, reverting to port " +
1560 "from topo file" )
1561 port = self.port
1562 url = "/network/configuration"
1563 if subjectClass:
1564 url += "/" + subjectClass
1565 if subjectKey:
1566 url += "/" + subjectKey
1567 if configKey:
1568 url += "/" + configKey
suibin zhang116647a2016-05-06 16:30:09 -07001569 response = self.send( method="POST",
suibin zhangd5b6fe42016-05-12 08:48:58 -07001570 url=url, ip = ip, port = port,
Jon Hall66e001c2015-11-12 09:45:10 -08001571 data=json.dumps( cfgJson ) )
1572 if response:
1573 if 200 <= response[ 0 ] <= 299:
1574 main.log.info( self.name + ": Successfully POST cfg" )
1575 return main.TRUE
1576 else:
1577 main.log.error( "Error with REST request, response was: " +
1578 str( response ) )
1579 return main.FALSE
1580 except ( AttributeError, TypeError ):
1581 main.log.exception( self.name + ": Object not as expected" )
1582 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 removeNetCfg( self, ip="DEFAULT", port="DEFAULT",
1588 subjectClass=None, subjectKey=None, configKey=None ):
1589 """
1590 Description:
1591 Remove a json object from the ONOS network configurations
1592 Returns:
1593 Returns main.TRUE for successful requests; Returns main.FALSE
1594 if error on requests;
1595 Returns None for exceptions
1596
1597 """
1598 try:
1599 output = None
1600 if ip == "DEFAULT":
1601 main.log.warn( "No ip given, reverting to ip from topo file" )
1602 ip = self.ip_address
1603 if port == "DEFAULT":
1604 main.log.warn( "No port given, reverting to port " +
1605 "from topo file" )
1606 port = self.port
1607 url = "/network/configuration"
1608 if subjectClass:
1609 url += "/" + subjectClass
1610 if subjectKey:
1611 url += "/" + subjectKey
1612 if configKey:
1613 url += "/" + configKey
suibin zhang116647a2016-05-06 16:30:09 -07001614 response = self.send( method="DELETE",
suibin zhangd5b6fe42016-05-12 08:48:58 -07001615 url=url, ip = ip, port = port )
Jon Hall66e001c2015-11-12 09:45:10 -08001616 if response:
1617 if 200 <= response[ 0 ] <= 299:
1618 main.log.info( self.name + ": Successfully delete cfg" )
1619 return main.TRUE
1620 else:
1621 main.log.error( "Error with REST request, response was: " +
1622 str( response ) )
1623 return main.FALSE
1624 except ( AttributeError, TypeError ):
1625 main.log.exception( self.name + ": Object not as expected" )
1626 return None
1627 except Exception:
1628 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001629 main.cleanAndExit()
suibin zhang17308622016-04-14 15:45:30 -07001630
1631 def createFlowBatch( self,
1632 numSw = 1,
1633 swIndex = 1,
1634 batchSize = 1,
1635 batchIndex = 1,
1636 deviceIdpreFix = "of:",
1637 appId=0,
1638 deviceID="",
1639 ingressPort="",
1640 egressPort="",
1641 ethType="",
1642 ethSrc="",
1643 ethDst="",
1644 vlan="",
1645 ipProto="",
1646 ipSrc=(),
1647 ipDst=(),
1648 tcpSrc="",
1649 tcpDst="",
1650 udpDst="",
1651 udpSrc="",
1652 mpls="",
1653 ip="DEFAULT",
1654 port="DEFAULT",
1655 debug=False ):
1656 """
1657 Description:
1658 Creates batches of MAC-rule flows for POST.
1659 Predefined MAC: 2 MS Hex digit for iterating devices
1660 Next 5 Hex digit for iterating batch numbers
1661 Next 5 Hex digit for iterating flows within a batch
1662 Required:
1663 * deviceId: id of the device
1664 Optional:
1665 * ingressPort: port ingress device
1666 * egressPort: port of egress device
1667 * ethType: specify ethType
1668 * ethSrc: specify ethSrc ( i.e. src mac addr )
1669 * ethDst: specify ethDst ( i.e. dst mac addr )
1670 * ipProto: specify ip protocol
1671 * ipSrc: specify ip source address with mask eg. ip#/24
1672 as a tuple (type, ip#)
1673 * ipDst: specify ip destination address eg. ip#/24
1674 as a tuple (type, ip#)
1675 * tcpSrc: specify tcp source port
1676 * tcpDst: specify tcp destination port
1677 Returns:
1678 Returns main.TRUE for successful requests; Returns main.FALSE
1679 if error on requests;
1680 Returns None for exceptions
1681 NOTE:
1682 The ip and port option are for the requests input's ip and port
1683 of the ONOS node
1684 """
1685 #from pprint import pprint
1686
1687 flowJsonList = []
1688 flowJsonBatch = {"flows":flowJsonList}
1689 dev = swIndex
1690
1691 for fl in range(1, batchSize + 1):
1692 flowJson = { "priority":100,
1693 "deviceId":"",
1694 "isPermanent":"true",
1695 "timeout":0,
1696 "treatment":{"instructions":[]},
1697 "selector": {"criteria":[]}}
1698
1699 #main.log.info("fl: " + str(fl))
1700 if dev <= numSw:
1701 deviceId = deviceIdpreFix + "{0:0{1}x}".format(dev,16)
1702 #print deviceId
1703 flowJson['deviceId'] = deviceId
1704 dev += 1
1705 else:
1706 dev = 1
1707 deviceId = deviceIdpreFix + "{0:0{1}x}".format(dev,16)
1708 #print deviceId
1709 flowJson['deviceId'] = deviceId
1710 dev += 1
1711
1712 # ethSrc starts with "0"; ethDst starts with "1"
1713 # 2 Hex digit of device number; 5 digits of batch index number; 5 digits of batch size
1714 ethS = "%02X" %int( "0" + "{0:0{1}b}".format(dev,7), 2 ) + \
1715 "{0:0{1}x}".format(batchIndex,5) + "{0:0{1}x}".format(fl,5)
1716 ethSrc = ':'.join(ethS[i:i+2] for i in range(0,len(ethS),2))
1717 ethD = "%02X" %int( "1" + "{0:0{1}b}".format(dev,7), 2 ) + \
1718 "{0:0{1}x}".format(batchIndex,5) + "{0:0{1}x}".format(fl,5)
1719 ethDst = ':'.join(ethD[i:i+2] for i in range(0,len(ethD),2))
1720
1721 if appId:
1722 flowJson[ "appId" ] = appId
1723
1724 if egressPort:
1725 flowJson[ 'treatment' ][ 'instructions' ].append( {
1726 "type":"OUTPUT",
1727 "port":egressPort } )
1728 if ingressPort:
1729 flowJson[ 'selector' ][ 'criteria' ].append( {
1730 "type":"IN_PORT",
1731 "port":ingressPort } )
1732 if ethType:
1733 flowJson[ 'selector' ][ 'criteria' ].append( {
1734 "type":"ETH_TYPE",
1735 "ethType":ethType } )
1736 if ethSrc:
1737 flowJson[ 'selector' ][ 'criteria' ].append( {
1738 "type":"ETH_SRC",
1739 "mac":ethSrc } )
1740 if ethDst:
1741 flowJson[ 'selector' ][ 'criteria' ].append( {
1742 "type":"ETH_DST",
1743 "mac":ethDst } )
1744 if vlan:
1745 flowJson[ 'selector' ][ 'criteria' ].append( {
1746 "type":"VLAN_VID",
1747 "vlanId":vlan } )
1748 if mpls:
1749 flowJson[ 'selector' ][ 'criteria' ].append( {
1750 "type":"MPLS_LABEL",
1751 "label":mpls } )
1752 if ipSrc:
1753 flowJson[ 'selector' ][ 'criteria' ].append( {
1754 "type":ipSrc[0],
1755 "ip":ipSrc[1] } )
1756 if ipDst:
1757 flowJson[ 'selector' ][ 'criteria' ].append( {
1758 "type":ipDst[0],
1759 "ip":ipDst[1] } )
1760 if tcpSrc:
1761 flowJson[ 'selector' ][ 'criteria' ].append( {
1762 "type":"TCP_SRC",
1763 "tcpPort": tcpSrc } )
1764 if tcpDst:
1765 flowJson[ 'selector' ][ 'criteria' ].append( {
1766 "type":"TCP_DST",
1767 "tcpPort": tcpDst } )
1768 if udpSrc:
1769 flowJson[ 'selector' ][ 'criteria' ].append( {
1770 "type":"UDP_SRC",
1771 "udpPort": udpSrc } )
1772 if udpDst:
1773 flowJson[ 'selector' ][ 'criteria' ].append( {
1774 "type":"UDP_DST",
1775 "udpPort": udpDst } )
1776 if ipProto:
1777 flowJson[ 'selector' ][ 'criteria' ].append( {
1778 "type":"IP_PROTO",
1779 "protocol": ipProto } )
1780 #pprint(flowJson)
1781 flowJsonList.append(flowJson)
1782
1783 main.log.info("Number of flows in batch: " + str( len(flowJsonList) ) )
1784 flowJsonBatch['flows'] = flowJsonList
1785 #pprint(flowJsonBatch)
1786
1787 return flowJsonBatch
1788
1789
1790 def sendFlowBatch( self, batch={}, ip="DEFAULT", port="DEFAULT", debug=False ):
1791 """
1792 Description:
1793 Sends a single flow batch through /flows REST API.
1794 Required:
1795 * The batch of flows
1796 Returns:
1797 Returns main.TRUE for successful requests; Returns main.FALSE
1798 if error on requests;
1799 Returns None for exceptions
1800 NOTE:
1801 The ip and port option are for the requests input's ip and port
1802 of the ONOS node
1803 """
1804 import time
1805
1806 try:
1807 if debug: main.log.debug( "Adding flow: " + self.pprint( batch ) )
1808 output = None
1809 if ip == "DEFAULT":
1810 main.log.warn( "No ip given, reverting to ip from topo file" )
1811 ip = self.ip_address
1812 if port == "DEFAULT":
1813 main.log.warn( "No port given, reverting to port " +
1814 "from topo file" )
1815 port = self.port
1816 url = "/flows/"
suibin zhang116647a2016-05-06 16:30:09 -07001817 response = self.send( method="POST",
suibin zhangd5b6fe42016-05-12 08:48:58 -07001818 url=url, ip = ip, port = port,
suibin zhang17308622016-04-14 15:45:30 -07001819 data=json.dumps( batch ) )
1820 #main.log.info("Post response is: ", str(response[0]))
1821 if response[0] == 200:
1822 main.log.info( self.name + ": Successfully POST flow batch" )
1823 return main.TRUE, response
1824 else:
1825 main.log.error( "Error with REST request, response was: " +
1826 str( response ) )
You Wang7b5b2262016-11-10 13:54:56 -08001827 return main.FALSE, response
suibin zhang17308622016-04-14 15:45:30 -07001828 except NotImplementedError as e:
1829 raise e # Inform the caller
1830 except ( AttributeError, TypeError ):
1831 main.log.exception( self.name + ": Object not as expected" )
You Wang7b5b2262016-11-10 13:54:56 -08001832 return None, None
suibin zhang17308622016-04-14 15:45:30 -07001833 except Exception:
1834 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001835 main.cleanAndExit()
suibin zhang17308622016-04-14 15:45:30 -07001836
1837 def removeFlowBatch( self, batch={},
1838 ip="DEFAULT", port="DEFAULT" ):
1839 """
1840 Description:
1841 Remove a batch of flows
1842 Required:
1843 flow batch
1844 Return:
1845 Returns main.TRUE if successfully deletes flows, otherwise
1846 Returns main.FALSE, Returns None on error
1847 """
1848 try:
1849 output = None
1850 if ip == "DEFAULT":
1851 main.log.warn( "No ip given, reverting to ip from topo file" )
1852 ip = self.ip_address
1853 if port == "DEFAULT":
1854 main.log.warn( "No port given, reverting to port " +
1855 "from topo file" )
1856 port = self.port
1857 # NOTE: REST url requires the intent id to be in decimal form
1858
suibin zhang116647a2016-05-06 16:30:09 -07001859 response = self.send( method="DELETE",
suibin zhangd5b6fe42016-05-12 08:48:58 -07001860 url="/flows/", ip = ip, port = port,
suibin zhang17308622016-04-14 15:45:30 -07001861 data = json.dumps(batch) )
1862 if response:
1863 if 200 <= response[ 0 ] <= 299:
1864 return main.TRUE
1865 else:
1866 main.log.error( "Error with REST request, response was: " +
1867 str( response ) )
1868 return main.FALSE
1869 except ( AttributeError, TypeError ):
1870 main.log.exception( self.name + ": Object not as expected" )
1871 return None
1872 except Exception:
1873 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001874 main.cleanAndExit()
Jeremy Songsterbc2d8ac2016-05-04 11:25:42 -07001875
1876 def getTopology( self, topologyOutput ):
1877 """
1878 Definition:
1879 Loads a json topology output
1880 Return:
1881 topology = current ONOS topology
1882 """
1883 import json
1884 try:
1885 # either onos:topology or 'topology' will work in CLI
1886 topology = json.loads(topologyOutput)
1887 main.log.debug( topology )
1888 return topology
1889 except pexpect.EOF:
1890 main.log.error( self.name + ": EOF exception found" )
1891 main.log.error( self.name + ": " + self.handle.before )
Devin Lim44075962017-08-11 10:56:37 -07001892 main.cleanAndExit()
Jeremy Songsterbc2d8ac2016-05-04 11:25:42 -07001893 except Exception:
1894 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001895 main.cleanAndExit()
Jeremy Songsterbc2d8ac2016-05-04 11:25:42 -07001896
1897 def checkStatus(
1898 self,
Devin Lim142b5342017-07-20 15:22:39 -07001899 numswitch,
1900 numlink,
Jeremy Songsterbc2d8ac2016-05-04 11:25:42 -07001901 logLevel="info" ):
1902 """
1903 Checks the number of switches & links that ONOS sees against the
1904 supplied values. By default this will report to main.log, but the
1905 log level can be specific.
1906
Devin Lim142b5342017-07-20 15:22:39 -07001907 Params: numswitch = expected number of switches
1908 numlink = expected number of links
Jeremy Songsterbc2d8ac2016-05-04 11:25:42 -07001909 logLevel = level to log to.
1910 Currently accepts 'info', 'warn' and 'report'
1911
1912 Returns: main.TRUE if the number of switches and links are correct,
1913 main.FALSE if the number of switches and links is incorrect,
1914 and main.ERROR otherwise
1915 """
1916 try:
Flavio Castro82ee2f62016-06-07 15:04:12 -07001917 topology = self.getTopology( self.topology() )
Devin Lim142b5342017-07-20 15:22:39 -07001918 #summary = self.summary()
Jeremy Songsterbc2d8ac2016-05-04 11:25:42 -07001919 if topology == {}:
1920 return main.ERROR
1921 output = ""
1922 # Is the number of switches is what we expected
1923 devices = topology.get( 'devices', False )
1924 links = topology.get( 'links', False )
Devin Lim142b5342017-07-20 15:22:39 -07001925 if devices is False or links is False:
Jeremy Songsterbc2d8ac2016-05-04 11:25:42 -07001926 return main.ERROR
Devin Lim142b5342017-07-20 15:22:39 -07001927 switchCheck = ( int( devices ) == int( numswitch ) )
Jeremy Songsterbc2d8ac2016-05-04 11:25:42 -07001928 # Is the number of links is what we expected
Devin Lim142b5342017-07-20 15:22:39 -07001929 linkCheck = ( int( links ) == int( numlink ) )
1930 if switchCheck and linkCheck:
Jeremy Songsterbc2d8ac2016-05-04 11:25:42 -07001931 # We expected the correct numbers
1932 output = output + "The number of links and switches match "\
1933 + "what was expected"
1934 result = main.TRUE
1935 else:
1936 output = output + \
1937 "The number of links and switches does not match " + \
1938 "what was expected"
1939 result = main.FALSE
1940 output = output + "\n ONOS sees %i devices" % int( devices )
Devin Lim142b5342017-07-20 15:22:39 -07001941 output = output + " (%i expected) " % int( numswitch )
Jeremy Songsterbc2d8ac2016-05-04 11:25:42 -07001942 output = output + "and %i links " % int( links )
Devin Lim142b5342017-07-20 15:22:39 -07001943 output = output + "(%i expected)" % int( numlink )
Jeremy Songsterbc2d8ac2016-05-04 11:25:42 -07001944 if logLevel == "report":
1945 main.log.report( output )
1946 elif logLevel == "warn":
1947 main.log.warn( output )
1948 else:
1949 main.log.info( output )
1950 return result
1951 except pexpect.EOF:
1952 main.log.error( self.name + ": EOF exception found" )
1953 main.log.error( self.name + ": " + self.handle.before )
Devin Lim44075962017-08-11 10:56:37 -07001954 main.cleanAndExit()
Jeremy Songsterbc2d8ac2016-05-04 11:25:42 -07001955 except Exception:
1956 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001957 main.cleanAndExit()
kavitha Alagesan373e0552016-11-22 05:22:05 +05301958
1959 def addGroup( self, deviceId, groupType, bucketList, appCookie, groupId, ip="DEFAULT", port="DEFAULT", debug=False ):
1960 """
1961 Description:
1962 Creates a single Group for the specified device.
1963 Required:
1964 * deviceId: id of the device
1965 * type: Type of the Group
1966 * bucketList: Buckets to be added to the group
1967 * appCookie: Cookie for the Group
1968 * groupId: Id of the Group
1969 Returns:
1970 Returns main.TRUE for successful requests; Returns main.FALSE
1971 if error on requests;
1972 Returns None for exceptions
1973 Note:
1974 The ip and port option are for the requests input's ip and port
1975 of the ONOS node
1976 """
1977 try:
1978 groupJson = { "type": groupType,
1979 "appCookie": appCookie,
1980 "groupId": groupId,
1981 "buckets": bucketList
1982 }
1983 return self.sendGroup( deviceId=deviceId, groupJson=groupJson, ip="DEFAULT", port="DEFAULT", debug=False )
1984
1985 except ( AttributeError, TypeError ):
1986 main.log.exception( self.name + ": Object not as expected" )
1987 return None
1988 except Exception:
1989 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07001990 main.cleanAndExit()
kavitha Alagesan373e0552016-11-22 05:22:05 +05301991
1992 def sendGroup( self, deviceId, groupJson, ip="DEFAULT", port="DEFAULT", debug=False ):
1993 """
1994 Description:
1995 Sends a single group to the specified device.
1996 Required:
1997 * deviceId: id of the device
1998 * groupJson: the group in json
1999 Returns:
2000 Returns main.TRUE for successful requests; Returns main.FALSE
2001 if error on requests;
2002 Returns None for exceptions
2003 NOTE:
2004 The ip and port option are for the requests input's ip and port
2005 of the ONOS node
2006 """
2007 try:
2008 if debug: main.log.debug( "Adding group: " + self.pprint( groupJson ) )
2009 output = None
2010 if ip == "DEFAULT":
2011 main.log.warn( "No ip given, reverting to ip from topo file" )
2012 ip = self.ip_address
2013 if port == "DEFAULT":
2014 main.log.warn( "No port given, reverting to port " +
2015 "from topo file" )
2016 port = self.port
2017 url = "/groups/" + deviceId
2018 response = self.send( method="POST",
2019 url=url, ip = ip, port = port,
2020 data=json.dumps( groupJson ) )
2021 if response:
2022 if "201" in str( response[ 0 ] ):
2023 main.log.info( self.name + ": Successfully POST group " +
2024 "in device: " + str( deviceId ) )
2025 return main.TRUE
2026 else:
2027 main.log.error( "Error with REST request, response was: " +
2028 str( response ) )
2029 return main.FALSE
2030 except NotImplementedError as e:
2031 raise e # Inform the caller
2032 except ( AttributeError, TypeError ):
2033 main.log.exception( self.name + ": Object not as expected" )
2034 return None
2035 except Exception:
2036 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07002037 main.cleanAndExit()
kavitha Alagesan373e0552016-11-22 05:22:05 +05302038
2039 def getGroups( self, deviceId=None, appCookie=None, ip="DEFAULT", port="DEFAULT" ):
2040 """
2041 Description:
2042 Get all the groups or get a specific group by giving the
2043 deviceId and appCookie
2044 Optional:
2045 * deviceId: id of the Device
2046 * appCookie: Cookie of the Group
2047 Returns:
2048 Returns Groups for successful requests; Returns main.FALSE
2049 if error on requests;
2050 Returns None for exceptions
2051 NOTE:
2052 The ip and port option are for the requests input's ip and port
2053 of the ONOS node
2054 """
2055 try:
2056 output = None
2057 if ip == "DEFAULT":
2058 main.log.warn( "No ip given, reverting to ip from topo file" )
2059 ip = self.ip_address
2060 if port == "DEFAULT":
2061 main.log.warn( "No port given, reverting to port " +
2062 "from topo file" )
2063 port = self.port
2064 url = "/groups"
2065 if deviceId:
2066 url += "/" + deviceId
2067 if appCookie:
2068 url += "/" + appCookie
2069 response = self.send( url=url, ip = ip, port = port )
2070 if response:
2071 if 200 <= response[ 0 ] <= 299:
2072 output = response[ 1 ]
2073 groupsJson = json.loads( output ).get( 'groups' )
2074 assert groupsJson is not None, "Error parsing json object"
2075 groups = json.dumps( groupsJson )
2076 return groups
2077 else:
2078 main.log.error( "Error with REST request, response was: " +
2079 str( response ) )
2080 return main.FALSE
2081 except ( AttributeError, AssertionError, TypeError ):
2082 main.log.exception( self.name + ": Object not as expected" )
2083 return None
2084 except Exception:
2085 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07002086 main.cleanAndExit()
kavitha Alagesan373e0552016-11-22 05:22:05 +05302087
2088 def removeGroup( self, deviceId, appCookie,
2089 ip="DEFAULT", port="DEFAULT" ):
2090 """
2091 Description:
2092 Removes specific device group
2093 Required:
2094 * deviceId: id of the Device
2095 * appCookie: Cookie of the Group
2096 Returns:
2097 Returns main.TRUE for successful requests; Returns main.FALSE
2098 if error on requests;
2099 Returns None for exceptions
2100 NOTE:
2101 The ip and port option are for the requests input's ip and port
2102 of the ONOS node
2103
2104 """
2105 try:
2106 output = None
2107 if ip == "DEFAULT":
2108 main.log.warn( "No ip given, reverting to ip from topo file" )
2109 ip = self.ip_address
2110 if port == "DEFAULT":
2111 main.log.warn( "No port given, reverting to port " +
2112 "from topo file" )
2113 port = self.port
2114 query = "/" + str( deviceId ) + "/" + str( appCookie )
2115 response = self.send( method="DELETE",
2116 url="/groups" + query, ip = ip, port = port )
2117 if response:
2118 if 200 <= response[ 0 ] <= 299:
2119 return main.TRUE
2120 else:
2121 main.log.error( "Error with REST request, response was: " +
2122 str( response ) )
2123 return main.FALSE
2124 except ( AttributeError, TypeError ):
2125 main.log.exception( self.name + ": Object not as expected" )
2126 return None
2127 except Exception:
2128 main.log.exception( self.name + ": Uncaught exception!" )
Devin Lim44075962017-08-11 10:56:37 -07002129 main.cleanAndExit()
kavitha Alagesan373e0552016-11-22 05:22:05 +05302130