blob: 2a62276bfac4a8f2d4339d7c25e35e7c5728293b [file] [log] [blame]
Jon Hallfc915882015-07-14 13:33:17 -07001#!/usr/bin/env python
2"""
3Created on 07-08-2015
4
5 TestON is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 2 of the License, or
8 ( at your option ) any later version.
9
10 TestON is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with TestON. If not, see <http://www.gnu.org/licenses/>.
17
18"""
19import json
20import os
21import requests
kelvin-onlab03eb88d2015-07-22 10:29:02 -070022import types
Jon Halle401b092015-09-23 13:34:24 -070023import sys
suibin zhanga5875da2016-04-02 20:54:50 -070024from Queue import Queue
Jon Hallfc915882015-07-14 13:33:17 -070025
Jon Hallfc915882015-07-14 13:33:17 -070026from drivers.common.api.controllerdriver import Controller
27
28
29class OnosRestDriver( Controller ):
30
31 def __init__( self ):
Jon Hallf7234882015-08-28 13:16:31 -070032 self.pwd = None
33 self.user_name = "user"
Jon Hallfc915882015-07-14 13:33:17 -070034 super( Controller, self ).__init__()
35 self.ip_address = "localhost"
36 self.port = "8080"
Jon Halle401b092015-09-23 13:34:24 -070037 self.wrapped = sys.modules[ __name__ ]
Jon Hallfc915882015-07-14 13:33:17 -070038
39 def connect( self, **connectargs ):
40 try:
41 for key in connectargs:
42 vars( self )[ key ] = connectargs[ key ]
43 self.name = self.options[ 'name' ]
44 except Exception as e:
45 main.log.exception( e )
46 try:
47 if os.getenv( str( self.ip_address ) ) != None:
48 self.ip_address = os.getenv( str( self.ip_address ) )
49 else:
kelvin-onlab03eb88d2015-07-22 10:29:02 -070050 main.log.info( self.name + ": ip set to " + self.ip_address )
Jon Hallfc915882015-07-14 13:33:17 -070051 except KeyError:
52 main.log.info( "Invalid host name," +
53 "defaulting to 'localhost' instead" )
54 self.ip_address = 'localhost'
55 except Exception as inst:
56 main.log.error( "Uncaught exception: " + str( inst ) )
57
58 self.handle = super( OnosRestDriver, self ).connect()
59 return self.handle
60
Jon Halle401b092015-09-23 13:34:24 -070061 def pprint( self, jsonObject ):
62 """
63 Pretty Prints a json object
64
65 arguments:
66 jsonObject - a parsed json object
67 returns:
68 A formatted string for printing or None on error
69 """
70 try:
71 if isinstance( jsonObject, str ):
72 jsonObject = json.loads( jsonObject )
73 return json.dumps( jsonObject, sort_keys=True,
74 indent=4, separators=(',', ': '))
75 except ( TypeError, ValueError ):
76 main.log.exception( "Error parsing jsonObject" )
77 return None
78
Jon Hallfc915882015-07-14 13:33:17 -070079 def send( self, ip, port, url, base="/onos/v1", method="GET",
Jon Hallf7234882015-08-28 13:16:31 -070080 query=None, data=None, debug=False ):
Jon Hallfc915882015-07-14 13:33:17 -070081 """
82 Arguments:
83 str ip: ONOS IP Address
84 str port: ONOS REST Port
85 str url: ONOS REST url path.
86 NOTE that this is is only the relative path. IE "/devices"
87 str base: The base url for the given REST api. Applications could
88 potentially have their own base url
89 str method: HTTP method type
kelvin-onlab03eb88d2015-07-22 10:29:02 -070090 dict query: Dictionary to be sent in the query string for
Jon Hallfc915882015-07-14 13:33:17 -070091 the request
92 dict data: Dictionary to be sent in the body of the request
93 """
94 # TODO: Authentication - simple http (user,pass) tuple
95 # TODO: should we maybe just pass kwargs straight to response?
96 # TODO: Do we need to allow for other protocols besides http?
97 # ANSWER: Not yet, but potentially https with certificates
98 try:
99 path = "http://" + str( ip ) + ":" + str( port ) + base + url
Jon Hallf7234882015-08-28 13:16:31 -0700100 if self.user_name and self.pwd:
suibin zhangeb121c02015-11-04 12:06:38 -0800101 main.log.info("user/passwd is: " + self.user_name + "/" + self.pwd)
Jon Hallf7234882015-08-28 13:16:31 -0700102 auth = (self.user_name, self.pwd)
103 else:
104 auth=None
Jon Hallfc915882015-07-14 13:33:17 -0700105 main.log.info( "Sending request " + path + " using " +
106 method.upper() + " method." )
107 response = requests.request( method.upper(),
108 path,
109 params=query,
Jon Hallf7234882015-08-28 13:16:31 -0700110 data=data,
111 auth=auth )
112 if debug:
113 main.log.debug( response )
Jon Hallfc915882015-07-14 13:33:17 -0700114 return ( response.status_code, response.text.encode( 'utf8' ) )
115 except requests.exceptions:
116 main.log.exception( "Error sending request." )
117 return None
Jon Halle401b092015-09-23 13:34:24 -0700118 except Exception:
119 main.log.exception( self.name + ": Uncaught exception!" )
120 main.cleanup()
121 main.exit()
Jon Hallfc915882015-07-14 13:33:17 -0700122
123 def intents( self, ip="DEFAULT", port="DEFAULT" ):
124 """
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700125 Description:
126 Gets a list of dictionary of all intents in the system
127 Returns:
128 A list of dictionary of intents in string type to match the cli
129 version for now; Returns main.FALSE if error on request;
130 Returns None for exception
Jon Hallfc915882015-07-14 13:33:17 -0700131 """
132 try:
133 output = None
134 if ip == "DEFAULT":
135 main.log.warn( "No ip given, reverting to ip from topo file" )
136 ip = self.ip_address
137 if port == "DEFAULT":
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700138 main.log.warn( "No port given, reverting to port " +
139 "from topo file" )
Jon Hallfc915882015-07-14 13:33:17 -0700140 port = self.port
141 response = self.send( ip, port, url="/intents" )
142 if response:
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700143 if 200 <= response[ 0 ] <= 299:
144 output = response[ 1 ]
145 a = json.loads( output ).get( 'intents' )
Jon Halle401b092015-09-23 13:34:24 -0700146 assert a is not None, "Error parsing json object"
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700147 b = json.dumps( a )
148 return b
Jon Hallfc915882015-07-14 13:33:17 -0700149 else:
150 main.log.error( "Error with REST request, response was: " +
151 str( response ) )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700152 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700153 except ( AttributeError, AssertionError, TypeError ):
154 main.log.exception( self.name + ": Object not as expected" )
Jon Hallfc915882015-07-14 13:33:17 -0700155 return None
Jon Halle401b092015-09-23 13:34:24 -0700156 except Exception:
157 main.log.exception( self.name + ": Uncaught exception!" )
158 main.cleanup()
159 main.exit()
Jon Hallfc915882015-07-14 13:33:17 -0700160
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700161 def intent( self, intentId, appId="org.onosproject.cli",
162 ip="DEFAULT", port="DEFAULT" ):
Jon Hallfc915882015-07-14 13:33:17 -0700163 """
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700164 Description:
165 Get the specific intent information of the given application ID and
166 intent ID
167 Required:
168 str intentId - Intent id in hexadecimal form
169 Optional:
170 str appId - application id of intent
171 Returns:
172 Returns an information dictionary of the given intent;
173 Returns main.FALSE if error on requests; Returns None for exception
174 NOTE:
175 The GET /intents REST api command accepts application id but the
176 api will get updated to accept application name instead
Jon Hallfc915882015-07-14 13:33:17 -0700177 """
178 try:
179 output = None
180 if ip == "DEFAULT":
181 main.log.warn( "No ip given, reverting to ip from topo file" )
182 ip = self.ip_address
183 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -0700184 main.log.warn( "No port given, reverting to port " +
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700185 "from topo file" )
Jon Hallfc915882015-07-14 13:33:17 -0700186 port = self.port
187 # NOTE: REST url requires the intent id to be in decimal form
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700188 query = "/" + str( appId ) + "/" + str( intentId )
Jon Hallfc915882015-07-14 13:33:17 -0700189 response = self.send( ip, port, url="/intents" + query )
190 if response:
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700191 if 200 <= response[ 0 ] <= 299:
192 output = response[ 1 ]
193 a = json.loads( output )
194 return a
Jon Hallfc915882015-07-14 13:33:17 -0700195 else:
196 main.log.error( "Error with REST request, response was: " +
197 str( response ) )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700198 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700199 except ( AttributeError, TypeError ):
200 main.log.exception( self.name + ": Object not as expected" )
Jon Hallfc915882015-07-14 13:33:17 -0700201 return None
Jon Halle401b092015-09-23 13:34:24 -0700202 except Exception:
203 main.log.exception( self.name + ": Uncaught exception!" )
204 main.cleanup()
205 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700206
207 def getIntentsId( self, ip="DEFAULT", port="DEFAULT" ):
208 """
209 Description:
210 Gets all intents ID using intents function
211 Returns:
212 List of intents ID;Returns None for exception; Returns None for
213 exception; Returns None for exception
214 """
215 try:
216 intentsDict = {}
217 intentsIdList = []
218 intentsDict = json.loads( self.intents( ip=ip, port=port ) )
219 for intent in intentsDict:
220 intentsIdList.append( intent.get( 'id' ) )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700221 if not intentsIdList:
222 main.log.debug( "Cannot find any intents" )
223 return main.FALSE
224 else:
225 main.log.info( "Found intents: " + str( intentsIdList ) )
226 return main.TRUE
Jon Halle401b092015-09-23 13:34:24 -0700227 except ( AttributeError, TypeError ):
228 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700229 return None
Jon Halle401b092015-09-23 13:34:24 -0700230 except Exception:
231 main.log.exception( self.name + ": Uncaught exception!" )
232 main.cleanup()
233 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700234
235 def apps( self, ip="DEFAULT", port="DEFAULT" ):
236 """
237 Description:
238 Returns all the current application installed in the system
239 Returns:
240 List of dictionary of installed application; Returns main.FALSE for
241 error on request; Returns None for exception
242 """
243 try:
244 output = None
245 if ip == "DEFAULT":
246 main.log.warn( "No ip given, reverting to ip from topo file" )
247 ip = self.ip_address
248 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -0700249 main.log.warn( "No port given, reverting to port " +
250 "from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700251 port = self.port
252 response = self.send( ip, port, url="/applications" )
253 if response:
254 if 200 <= response[ 0 ] <= 299:
255 output = response[ 1 ]
256 a = json.loads( output ).get( 'applications' )
Jon Halle401b092015-09-23 13:34:24 -0700257 assert a is not None, "Error parsing json object"
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700258 b = json.dumps( a )
259 return b
260 else:
261 main.log.error( "Error with REST request, response was: " +
262 str( response ) )
263 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700264 except ( AttributeError, AssertionError, TypeError ):
265 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700266 return None
Jon Halle401b092015-09-23 13:34:24 -0700267 except Exception:
268 main.log.exception( self.name + ": Uncaught exception!" )
269 main.cleanup()
270 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700271
272 def activateApp( self, appName, ip="DEFAULT", port="DEFAULT", check=True ):
273 """
274 Decription:
275 Activate an app that is already installed in ONOS
276 Optional:
277 bool check - If check is True, method will check the status
278 of the app after the command is issued
279 Returns:
280 Returns main.TRUE if the command was successfully or main.FALSE
281 if the REST responded with an error or given incorrect input;
282 Returns None for exception
283
284 """
285 try:
286 output = None
287 if ip == "DEFAULT":
288 main.log.warn( "No ip given, reverting to ip from topo file" )
289 ip = self.ip_address
290 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -0700291 main.log.warn( "No port given, reverting to port " +
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700292 "from topo file" )
293 port = self.port
294 query = "/" + str( appName ) + "/active"
295 response = self.send( ip, port, method="POST",
296 url="/applications" + query )
297 if response:
298 output = response[ 1 ]
299 app = json.loads( output )
300 if 200 <= response[ 0 ] <= 299:
301 if check:
302 if app.get( 'state' ) == 'ACTIVE':
303 main.log.info( self.name + ": " + appName +
304 " application" +
305 " is in ACTIVE state" )
306 return main.TRUE
307 else:
308 main.log.error( self.name + ": " + appName +
309 " application" + " is in " +
310 app.get( 'state' ) + " state" )
311 return main.FALSE
312 else:
313 main.log.warn( "Skipping " + appName +
314 "application check" )
315 return main.TRUE
316 else:
317 main.log.error( "Error with REST request, response was: " +
318 str( response ) )
319 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700320 except ( AttributeError, TypeError ):
321 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700322 return None
Jon Halle401b092015-09-23 13:34:24 -0700323 except Exception:
324 main.log.exception( self.name + ": Uncaught exception!" )
325 main.cleanup()
326 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700327
328 def deactivateApp( self, appName, ip="DEFAULT", port="DEFAULT",
329 check=True ):
330 """
331 Required:
332 Deactivate an app that is already activated in ONOS
333 Optional:
334 bool check - If check is True, method will check the status of the
335 app after the command is issued
336 Returns:
337 Returns main.TRUE if the command was successfully sent
338 main.FALSE if the REST responded with an error or given
339 incorrect input; Returns None for exception
340 """
341 try:
342 output = None
343 if ip == "DEFAULT":
344 main.log.warn( "No ip given, reverting to ip from topo file" )
345 ip = self.ip_address
346 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -0700347 main.log.warn( "No port given, reverting to port " +
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700348 "from topo file" )
349 port = self.port
350 query = "/" + str( appName ) + "/active"
351 response = self.send( ip, port, method="DELETE",
352 url="/applications" + query )
353 if response:
354 output = response[ 1 ]
355 app = json.loads( output )
356 if 200 <= response[ 0 ] <= 299:
357 if check:
358 if app.get( 'state' ) == 'INSTALLED':
359 main.log.info( self.name + ": " + appName +
360 " application" +
361 " is in INSTALLED state" )
362 return main.TRUE
363 else:
364 main.log.error( self.name + ": " + appName +
365 " application" + " is in " +
366 app.get( 'state' ) + " state" )
367 return main.FALSE
368 else:
369 main.log.warn( "Skipping " + appName +
370 "application check" )
371 return main.TRUE
372 else:
373 main.log.error( "Error with REST request, response was: " +
374 str( response ) )
375 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700376 except ( AttributeError, TypeError ):
377 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700378 return None
Jon Halle401b092015-09-23 13:34:24 -0700379 except Exception:
380 main.log.exception( self.name + ": Uncaught exception!" )
381 main.cleanup()
382 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700383
384 def getApp( self, appName, project="org.onosproject.", ip="DEFAULT",
385 port="DEFAULT" ):
386 """
387 Decription:
388 Gets the informaion of the given application
389 Required:
390 str name - Name of onos application
391 Returns:
392 Returns a dictionary of information ONOS application in string type;
393 Returns main.FALSE if error on requests; Returns None for exception
394 """
395 try:
396 output = None
397 if ip == "DEFAULT":
398 main.log.warn( "No ip given, reverting to ip from topo file" )
399 ip = self.ip_address
400 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -0700401 main.log.warn( "No port given, reverting to port " +
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700402 "from topo file" )
403 port = self.port
404 query = "/" + project + str( appName )
405 response = self.send( ip, port, url="/applications" + query )
406 if response:
407 if 200 <= response[ 0 ] <= 299:
408 output = response[ 1 ]
409 a = json.loads( output )
410 return a
411 else:
412 main.log.error( "Error with REST request, response was: " +
413 str( response ) )
414 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700415 except ( AttributeError, TypeError ):
416 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700417 return None
Jon Halle401b092015-09-23 13:34:24 -0700418 except Exception:
419 main.log.exception( self.name + ": Uncaught exception!" )
420 main.cleanup()
421 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700422
423 def addHostIntent( self, hostIdOne, hostIdTwo, appId='org.onosproject.cli',
424 ip="DEFAULT", port="DEFAULT" ):
425 """
426 Description:
427 Adds a host-to-host intent ( bidirectional ) by
428 specifying the two hosts.
429 Required:
430 * hostIdOne: ONOS host id for host1
431 * hostIdTwo: ONOS host id for host2
432 Optional:
433 str appId - Application name of intent identifier
434 Returns:
kelvin-onlabb50074f2015-07-27 16:18:32 -0700435 Returns main.TRUE for successful requests; Returns main.FALSE if
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700436 error on requests; Returns None for exceptions
437 """
438 try:
439 intentJson = {"two": str( hostIdTwo ),
440 "selector": {"criteria": []}, "priority": 7,
441 "treatment": {"deferred": [], "instructions": []},
442 "appId": appId, "one": str( hostIdOne ),
443 "type": "HostToHostIntent",
444 "constraints": [{"type": "LinkTypeConstraint",
445 "types": ["OPTICAL"],
446 "inclusive": 'false' }]}
447 output = None
448 if ip == "DEFAULT":
449 main.log.warn( "No ip given, reverting to ip from topo file" )
450 ip = self.ip_address
451 if port == "DEFAULT":
452 main.log.warn( "No port given, reverting to port " +
453 "from topo file" )
454 port = self.port
455 response = self.send( ip,
456 port,
457 method="POST",
458 url="/intents",
459 data=json.dumps( intentJson ) )
460 if response:
461 if 201:
462 main.log.info( self.name + ": Successfully POST host" +
463 " intent between host: " + hostIdOne +
464 " and host: " + hostIdTwo )
465 return main.TRUE
466 else:
467 main.log.error( "Error with REST request, response was: " +
468 str( response ) )
469 return main.FALSE
470
Jon Halle401b092015-09-23 13:34:24 -0700471 except ( AttributeError, TypeError ):
472 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700473 return None
Jon Halle401b092015-09-23 13:34:24 -0700474 except Exception:
475 main.log.exception( self.name + ": Uncaught exception!" )
476 main.cleanup()
477 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700478
kelvin-onlabb50074f2015-07-27 16:18:32 -0700479 def addPointIntent( self,
480 ingressDevice,
481 egressDevice,
kelvin-onlabb50074f2015-07-27 16:18:32 -0700482 appId='org.onosproject.cli',
483 ingressPort="",
484 egressPort="",
485 ethType="",
486 ethSrc="",
487 ethDst="",
488 bandwidth="",
489 lambdaAlloc=False,
490 ipProto="",
491 ipSrc="",
492 ipDst="",
493 tcpSrc="",
kelvin-onlab9b42b0a2015-08-05 14:43:58 -0700494 tcpDst="",
495 ip="DEFAULT",
496 port="DEFAULT" ):
kelvin-onlabb50074f2015-07-27 16:18:32 -0700497 """
498 Description:
499 Adds a point-to-point intent ( uni-directional ) by
500 specifying device id's and optional fields
501 Required:
502 * ingressDevice: device id of ingress device
503 * egressDevice: device id of egress device
504 Optional:
505 * ethType: specify ethType
506 * ethSrc: specify ethSrc ( i.e. src mac addr )
507 * ethDst: specify ethDst ( i.e. dst mac addr )
508 * bandwidth: specify bandwidth capacity of link (TODO)
509 * lambdaAlloc: if True, intent will allocate lambda
510 for the specified intent (TODO)
511 * ipProto: specify ip protocol
512 * ipSrc: specify ip source address with mask eg. ip#/24
513 * ipDst: specify ip destination address eg. ip#/24
514 * tcpSrc: specify tcp source port
515 * tcpDst: specify tcp destination port
516 Returns:
517 Returns main.TRUE for successful requests; Returns main.FALSE if
518 no ingress|egress port found and if error on requests;
519 Returns None for exceptions
520 NOTE:
521 The ip and port option are for the requests input's ip and port
522 of the ONOS node
523 """
524 try:
525 if "/" in ingressDevice:
526 if not ingressPort:
527 ingressPort = ingressDevice.split( "/" )[ 1 ]
528 ingressDevice = ingressDevice.split( "/" )[ 0 ]
529 else:
530 if not ingressPort:
531 main.log.debug( self.name + ": Ingress port not specified" )
532 return main.FALSE
533
534 if "/" in egressDevice:
535 if not egressPort:
536 egressPort = egressDevice.split( "/" )[ 1 ]
537 egressDevice = egressDevice.split( "/" )[ 0 ]
538 else:
539 if not egressPort:
540 main.log.debug( self.name + ": Egress port not specified" )
541 return main.FALSE
542
543 intentJson ={ "ingressPoint": { "device": ingressDevice,
544 "port": ingressPort },
545 "selector": { "criteria": [] },
546 "priority": 55,
547 "treatment": { "deferred": [],
548 "instructions": [] },
549 "egressPoint": { "device": egressDevice,
550 "port": egressPort },
551 "appId": appId,
552 "type": "PointToPointIntent",
553 "constraints": [ { "type": "LinkTypeConstraint",
554 "types": [ "OPTICAL" ],
555 "inclusive": "false" } ] }
556
557 if ethType == "IPV4":
558 intentJson[ 'selector' ][ 'criteria' ].append( {
559 "type":"ETH_TYPE",
560 "ethType":2048 } )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -0700561 elif ethType:
562 intentJson[ 'selector' ][ 'criteria' ].append( {
563 "type":"ETH_TYPE",
564 "ethType":ethType } )
565
kelvin-onlabb50074f2015-07-27 16:18:32 -0700566 if ethSrc:
567 intentJson[ 'selector' ][ 'criteria' ].append(
568 { "type":"ETH_SRC",
569 "mac":ethSrc } )
570 if ethDst:
571 intentJson[ 'selector' ][ 'criteria' ].append(
572 { "type":"ETH_DST",
573 "mac":ethDst } )
574 if ipSrc:
575 intentJson[ 'selector' ][ 'criteria' ].append(
576 { "type":"IPV4_SRC",
577 "ip":ipSrc } )
578 if ipDst:
579 intentJson[ 'selector' ][ 'criteria' ].append(
580 { "type":"IPV4_DST",
581 "ip":ipDst } )
582 if tcpSrc:
583 intentJson[ 'selector' ][ 'criteria' ].append(
584 { "type":"TCP_SRC",
585 "tcpPort": tcpSrc } )
586 if tcpDst:
587 intentJson[ 'selector' ][ 'criteria' ].append(
588 { "type":"TCP_DST",
589 "tcpPort": tcpDst } )
590 if ipProto:
591 intentJson[ 'selector' ][ 'criteria' ].append(
592 { "type":"IP_PROTO",
593 "protocol": ipProto } )
594
595 # TODO: Bandwidth and Lambda will be implemented if needed
596
597 main.log.debug( intentJson )
598
599 output = None
600 if ip == "DEFAULT":
601 main.log.warn( "No ip given, reverting to ip from topo file" )
602 ip = self.ip_address
603 if port == "DEFAULT":
604 main.log.warn( "No port given, reverting to port " +
605 "from topo file" )
606 port = self.port
607 response = self.send( ip,
608 port,
609 method="POST",
610 url="/intents",
611 data=json.dumps( intentJson ) )
612 if response:
613 if 201:
614 main.log.info( self.name + ": Successfully POST point" +
615 " intent between ingress: " + ingressDevice +
616 " and egress: " + egressDevice + " devices" )
617 return main.TRUE
618 else:
619 main.log.error( "Error with REST request, response was: " +
620 str( response ) )
621 return main.FALSE
622
Jon Halle401b092015-09-23 13:34:24 -0700623 except ( AttributeError, TypeError ):
624 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlabb50074f2015-07-27 16:18:32 -0700625 return None
Jon Halle401b092015-09-23 13:34:24 -0700626 except Exception:
627 main.log.exception( self.name + ": Uncaught exception!" )
628 main.cleanup()
629 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700630
631 def removeIntent( self, intentId, appId='org.onosproject.cli',
632 ip="DEFAULT", port="DEFAULT" ):
633 """
634 Remove intent for specified application id and intent id;
635 Returns None for exception
636 """
637 try:
638 output = None
639 if ip == "DEFAULT":
640 main.log.warn( "No ip given, reverting to ip from topo file" )
641 ip = self.ip_address
642 if port == "DEFAULT":
643 main.log.warn( "No port given, reverting to port " +
644 "from topo file" )
645 port = self.port
646 # NOTE: REST url requires the intent id to be in decimal form
647 query = "/" + str( appId ) + "/" + str( int( intentId, 16 ) )
648 response = self.send( ip,
649 port,
650 method="DELETE",
651 url="/intents" + query )
652 if response:
653 if 200 <= response[ 0 ] <= 299:
654 return main.TRUE
655 else:
656 main.log.error( "Error with REST request, response was: " +
657 str( response ) )
658 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700659 except ( AttributeError, TypeError ):
660 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700661 return None
Jon Halle401b092015-09-23 13:34:24 -0700662 except Exception:
663 main.log.exception( self.name + ": Uncaught exception!" )
664 main.cleanup()
665 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700666
667 def getIntentsId( self, ip="DEFAULT", port="DEFAULT" ):
668 """
669 Returns a list of intents id; Returns None for exception
670 """
671 try:
672 intentIdList = []
673 intentsJson = json.loads( self.intents() )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700674 for intent in intentsJson:
675 intentIdList.append( intent.get( 'id' ) )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700676 return intentIdList
Jon Halle401b092015-09-23 13:34:24 -0700677 except ( AttributeError, TypeError ):
678 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700679 return None
Jon Halle401b092015-09-23 13:34:24 -0700680 except Exception:
681 main.log.exception( self.name + ": Uncaught exception!" )
682 main.cleanup()
683 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700684
685 def removeAllIntents( self, intentIdList ='ALL',appId='org.onosproject.cli',
686 ip="DEFAULT", port="DEFAULT", delay=5 ):
687 """
688 Description:
689 Remove all the intents
690 Returns:
691 Returns main.TRUE if all intents are removed, otherwise returns
692 main.FALSE; Returns None for exception
693 """
694 try:
695 results = []
696 if intentIdList == 'ALL':
697 intentIdList = self.getIntentsId( ip=ip, port=port )
698
699 main.log.info( self.name + ": Removing intents " +
700 str( intentIdList ) )
701
702 if isinstance( intentIdList, types.ListType ):
703 for intent in intentIdList:
704 results.append( self.removeIntent( intentId=intent,
705 appId=appId,
706 ip=ip,
707 port=port ) )
708 # Check for remaining intents
709 # NOTE: Noticing some delay on Deleting the intents so i put
710 # this time out
711 import time
712 time.sleep( delay )
713 intentRemain = len( json.loads( self.intents() ) )
714 if all( result==main.TRUE for result in results ) and \
715 intentRemain == 0:
716 main.log.info( self.name + ": All intents are removed " )
717 return main.TRUE
718 else:
719 main.log.error( self.name + ": Did not removed all intents,"
720 + " there are " + str( intentRemain )
721 + " intents remaining" )
722 return main.FALSE
723 else:
724 main.log.debug( self.name + ": There is no intents ID list" )
Jon Halle401b092015-09-23 13:34:24 -0700725 except ( AttributeError, TypeError ):
726 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700727 return None
Jon Halle401b092015-09-23 13:34:24 -0700728 except Exception:
729 main.log.exception( self.name + ": Uncaught exception!" )
730 main.cleanup()
731 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700732
733 def hosts( self, ip="DEFAULT", port="DEFAULT" ):
734 """
735 Description:
736 Get a list of dictionary of all discovered hosts
737 Returns:
738 Returns a list of dictionary of information of the hosts currently
739 discovered by ONOS; Returns main.FALSE if error on requests;
740 Returns None for exception
741 """
742 try:
743 output = None
744 if ip == "DEFAULT":
745 main.log.warn( "No ip given, reverting to ip from topo file" )
746 ip = self.ip_address
747 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -0700748 main.log.warn( "No port given, reverting to port " +
749 "from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700750 port = self.port
751 response = self.send( ip, port, url="/hosts" )
752 if response:
753 if 200 <= response[ 0 ] <= 299:
754 output = response[ 1 ]
755 a = json.loads( output ).get( 'hosts' )
Jon Halle401b092015-09-23 13:34:24 -0700756 assert a is not None, "Error parsing json object"
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700757 b = json.dumps( a )
758 return b
759 else:
760 main.log.error( "Error with REST request, response was: " +
761 str( response ) )
762 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700763 except ( AttributeError, AssertionError, TypeError ):
764 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700765 return None
Jon Halle401b092015-09-23 13:34:24 -0700766 except Exception:
767 main.log.exception( self.name + ": Uncaught exception!" )
768 main.cleanup()
769 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700770
771 def getHost( self, mac, vlan="-1", ip="DEFAULT", port="DEFAULT" ):
772 """
773 Description:
774 Gets the information from the given host
775 Required:
776 str mac - MAC address of the host
777 Optional:
778 str vlan - VLAN tag of the host, defaults to -1
779 Returns:
780 Return the host id from the hosts/mac/vlan output in REST api
781 whose 'id' contains mac/vlan; Returns None for exception;
782 Returns main.FALSE if error on requests
783
784 NOTE:
785 Not sure what this function should do, any suggestion?
786 """
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":
Jon Hallf7234882015-08-28 13:16:31 -0700793 main.log.warn( "No port given, reverting to port " +
794 "from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700795 port = self.port
796 query = "/" + mac + "/" + vlan
797 response = self.send( ip, port, url="/hosts" + query )
798 if response:
799 # NOTE: What if the person wants other values? would it be better
800 # to have a function that gets a key and return a value instead?
801 # This function requires mac and vlan and returns an ID which
802 # makes this current function useless
803 if 200 <= response[ 0 ] <= 299:
804 output = response[ 1 ]
805 hostId = json.loads( output ).get( 'id' )
806 return hostId
807 else:
808 main.log.error( "Error with REST request, response was: " +
809 str( response ) )
810 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700811 except ( AttributeError, TypeError ):
812 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700813 return None
Jon Halle401b092015-09-23 13:34:24 -0700814 except Exception:
815 main.log.exception( self.name + ": Uncaught exception!" )
816 main.cleanup()
817 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700818
819 def topology( self, ip="DEFAULT", port="DEFAULT" ):
820 """
821 Description:
822 Gets the overview of network topology
823 Returns:
824 Returns a dictionary containing information about network topology;
825 Returns None for exception
826 """
827 try:
828 output = None
829 if ip == "DEFAULT":
830 main.log.warn( "No ip given, reverting to ip from topo file" )
831 ip = self.ip_address
832 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -0700833 main.log.warn( "No port given, reverting to port " +
834 "from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700835 port = self.port
836 response = self.send( ip, port, url="/topology" )
837 if response:
838 if 200 <= response[ 0 ] <= 299:
839 output = response[ 1 ]
840 a = json.loads( output )
841 b = json.dumps( a )
842 return b
843 else:
844 main.log.error( "Error with REST request, response was: " +
845 str( response ) )
846 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700847 except ( AttributeError, TypeError ):
848 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700849 return None
Jon Halle401b092015-09-23 13:34:24 -0700850 except Exception:
851 main.log.exception( self.name + ": Uncaught exception!" )
852 main.cleanup()
853 main.exit()
854
855 def devices( self, ip="DEFAULT", port="DEFAULT" ):
856 """
857 Description:
858 Get the devices discovered by ONOS is json string format
859 Returns:
860 a json string of the devices currently discovered by ONOS OR
861 main.FALSE if there is an error in the request OR
862 Returns None for exception
863 """
864 try:
865 output = None
866 if ip == "DEFAULT":
867 main.log.warn( "No ip given, reverting to ip from topo file" )
868 ip = self.ip_address
869 if port == "DEFAULT":
870 main.log.warn( "No port given, reverting to port " +
871 "from topo file" )
872 port = self.port
873 response = self.send( ip, port, url="/devices" )
874 if response:
875 if 200 <= response[ 0 ] <= 299:
876 output = response[ 1 ]
877 a = json.loads( output ).get( 'devices' )
878 assert a is not None, "Error parsing json object"
879 b = json.dumps( a )
880 return b
881 else:
882 main.log.error( "Error with REST request, response was: " +
883 str( response ) )
884 return main.FALSE
885 except ( AttributeError, AssertionError, TypeError ):
886 main.log.exception( self.name + ": Object not as expected" )
887 return None
888 except Exception:
889 main.log.exception( self.name + ": Uncaught exception!" )
890 main.cleanup()
891 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700892
893 def getIntentState( self, intentsId, intentsJson=None,
894 ip="DEFAULT", port="DEFAULT" ):
895 """
896 Description:
897 Get intent state.
898 Accepts a single intent ID (string type) or a list of intent IDs.
899 Returns the state(string type) of the id if a single intent ID is
900 accepted.
901 Required:
902 intentId: intent ID (string type)
903 intentsJson: parsed json object from the onos:intents api
904 Returns:
905 Returns a dictionary with intent IDs as the key and its
906 corresponding states as the values; Returns None for invalid IDs or
907 Type error and any exceptions
908 NOTE:
909 An intent's state consist of INSTALLED,WITHDRAWN etc.
910 """
911 try:
912 state = "State is Undefined"
913 if not intentsJson:
914 intentsJsonTemp = json.loads( self.intents() )
915 else:
916 intentsJsonTemp = json.loads( intentsJson )
917 if isinstance( intentsId, types.StringType ):
918 for intent in intentsJsonTemp:
919 if intentsId == intent[ 'id' ]:
920 state = intent[ 'state' ]
921 return state
922 main.log.info( "Cannot find intent ID" + str( intentsId ) +
923 " on the list" )
924 return state
925 elif isinstance( intentsId, types.ListType ):
926 dictList = []
927 for i in xrange( len( intentsId ) ):
928 stateDict = {}
929 for intents in intentsJsonTemp:
930 if intentsId[ i ] == intents[ 'id' ]:
931 stateDict[ 'state' ] = intents[ 'state' ]
932 stateDict[ 'id' ] = intentsId[ i ]
933 dictList.append( stateDict )
934 break
935 if len( intentsId ) != len( dictList ):
936 main.log.info( "Cannot find some of the intent ID state" )
937 return dictList
938 else:
939 main.log.info( "Invalid intents ID entry" )
940 return None
941
Jon Halle401b092015-09-23 13:34:24 -0700942 except ( AttributeError, TypeError ):
943 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700944 return None
Jon Halle401b092015-09-23 13:34:24 -0700945 except Exception:
946 main.log.exception( self.name + ": Uncaught exception!" )
947 main.cleanup()
948 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700949
950 def checkIntentState( self, intentsId="ALL", expectedState='INSTALLED',
951 ip="DEFAULT", port="DEFAULT"):
952 """
953 Description:
954 Check intents state based on expected state which defaults to
955 INSTALLED state
956 Required:
957 intentsId - List of intents ID to be checked
958 Optional:
959 expectedState - Check the expected state(s) of each intents
960 state in the list.
961 *NOTE: You can pass in a list of expected state,
962 Eg: expectedState = [ 'INSTALLED' , 'INSTALLING' ]
963 Return:
964 Returns main.TRUE only if all intent are the same as expected states
965 , otherwise, returns main.FALSE; Returns None for general exception
966 """
967 try:
968 # Generating a dictionary: intent id as a key and state as value
969 returnValue = main.TRUE
970 if intentsId == "ALL":
971 intentsId = self.getIntentsId( ip=ip, port=port )
972 intentsDict = self.getIntentState( intentsId, ip=ip, port=port )
973
974 #print "len of intentsDict ", str( len( intentsDict ) )
975 if len( intentsId ) != len( intentsDict ):
976 main.log.error( self.name + ": There is something wrong " +
977 "getting intents state" )
978 return main.FALSE
979
980 if isinstance( expectedState, types.StringType ):
981 for intents in intentsDict:
982 if intents.get( 'state' ) != expectedState:
983 main.log.debug( self.name + " : Intent ID - " +
984 intents.get( 'id' ) +
985 " actual state = " +
986 intents.get( 'state' )
987 + " does not equal expected state = "
988 + expectedState )
989 returnValue = main.FALSE
990
991 elif isinstance( expectedState, types.ListType ):
992 for intents in intentsDict:
993 if not any( state == intents.get( 'state' ) for state in
994 expectedState ):
995 main.log.debug( self.name + " : Intent ID - " +
996 intents.get( 'id' ) +
997 " actual state = " +
998 intents.get( 'state' ) +
999 " does not equal expected states = "
1000 + str( expectedState ) )
1001 returnValue = main.FALSE
1002
1003 if returnValue == main.TRUE:
1004 main.log.info( self.name + ": All " +
1005 str( len( intentsDict ) ) +
1006 " intents are in " + str( expectedState ) +
1007 " state" )
1008 return returnValue
Jon Halle401b092015-09-23 13:34:24 -07001009 except ( AttributeError, TypeError ):
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001010 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001011 return None
Jon Halle401b092015-09-23 13:34:24 -07001012 except Exception:
1013 main.log.exception( self.name + ": Uncaught exception!" )
1014 main.cleanup()
1015 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001016
1017 def flows( self, ip="DEFAULT", port="DEFAULT" ):
1018 """
1019 Description:
1020 Get flows currently added to the system
1021 NOTE:
1022 The flows -j cli command has completely different format than
Jon Halle401b092015-09-23 13:34:24 -07001023 the REST output
1024
1025 Returns None for exception
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001026 """
1027 try:
1028 output = None
1029 if ip == "DEFAULT":
1030 main.log.warn( "No ip given, reverting to ip from topo file" )
1031 ip = self.ip_address
1032 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -07001033 main.log.warn( "No port given, reverting to port " +
1034 "from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001035 port = self.port
1036 response = self.send( ip, port, url="/flows" )
1037 if response:
1038 if 200 <= response[ 0 ] <= 299:
1039 output = response[ 1 ]
1040 a = json.loads( output ).get( 'flows' )
Jon Halle401b092015-09-23 13:34:24 -07001041 assert a is not None, "Error parsing json object"
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001042 b = json.dumps( a )
1043 return b
1044 else:
1045 main.log.error( "Error with REST request, response was: " +
1046 str( response ) )
1047 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -07001048 except ( AttributeError, AssertionError, TypeError ):
1049 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001050 return None
Jon Halle401b092015-09-23 13:34:24 -07001051 except Exception:
1052 main.log.exception( self.name + ": Uncaught exception!" )
1053 main.cleanup()
1054 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001055
Jon Halle401b092015-09-23 13:34:24 -07001056 def getFlows( self, deviceId, flowId=None, ip="DEFAULT", port="DEFAULT" ):
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001057 """
1058 Description:
1059 Gets all the flows of the device or get a specific flow in the
1060 device by giving its flow ID
1061 Required:
Jon Halle401b092015-09-23 13:34:24 -07001062 str deviceId - device/switch Id
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001063 Optional:
1064 int/hex flowId - ID of the flow
1065 """
1066 try:
1067 output = None
1068 if ip == "DEFAULT":
1069 main.log.warn( "No ip given, reverting to ip from topo file" )
1070 ip = self.ip_address
1071 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -07001072 main.log.warn( "No port given, reverting to port " +
1073 "from topo file" )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001074 port = self.port
Jon Halle401b092015-09-23 13:34:24 -07001075 url = "/flows/" + deviceId
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001076 if flowId:
1077 url += "/" + str( int( flowId ) )
1078 print url
1079 response = self.send( ip, port, url=url )
1080 if response:
1081 if 200 <= response[ 0 ] <= 299:
1082 output = response[ 1 ]
1083 a = json.loads( output ).get( 'flows' )
Jon Halle401b092015-09-23 13:34:24 -07001084 assert a is not None, "Error parsing json object"
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001085 b = json.dumps( a )
1086 return b
1087 else:
1088 main.log.error( "Error with REST request, response was: " +
1089 str( response ) )
1090 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -07001091 except ( AttributeError, AssertionError, TypeError ):
1092 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001093 return None
Jon Halle401b092015-09-23 13:34:24 -07001094 except Exception:
1095 main.log.exception( self.name + ": Uncaught exception!" )
1096 main.cleanup()
1097 main.exit()
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001098
GlennRC073e8bc2015-10-27 17:11:28 -07001099 def sendFlow( self, deviceId, flowJson, ip="DEFAULT", port="DEFAULT", debug=False ):
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001100 """
1101 Description:
GlennRC073e8bc2015-10-27 17:11:28 -07001102 Sends a single flow to the specified device. This function exists
1103 so you can bypass the addFLow driver and send your own custom flow.
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001104 Required:
GlennRC073e8bc2015-10-27 17:11:28 -07001105 * The flow in json
1106 * the device id to add the flow to
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001107 Returns:
1108 Returns main.TRUE for successful requests; Returns main.FALSE
1109 if error on requests;
1110 Returns None for exceptions
1111 NOTE:
1112 The ip and port option are for the requests input's ip and port
1113 of the ONOS node
1114 """
GlennRC073e8bc2015-10-27 17:11:28 -07001115
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001116 try:
GlennRC073e8bc2015-10-27 17:11:28 -07001117 if debug: main.log.debug( "Adding flow: " + self.pprint( flowJson ) )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001118 output = None
1119 if ip == "DEFAULT":
1120 main.log.warn( "No ip given, reverting to ip from topo file" )
1121 ip = self.ip_address
1122 if port == "DEFAULT":
1123 main.log.warn( "No port given, reverting to port " +
1124 "from topo file" )
1125 port = self.port
1126 url = "/flows/" + deviceId
1127 response = self.send( ip,
1128 port,
1129 method="POST",
1130 url=url,
1131 data=json.dumps( flowJson ) )
1132 if response:
1133 if 201:
1134 main.log.info( self.name + ": Successfully POST flow" +
1135 "in device: " + str( deviceId ) )
1136 return main.TRUE
1137 else:
1138 main.log.error( "Error with REST request, response was: " +
1139 str( response ) )
1140 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -07001141 except NotImplementedError as e:
1142 raise e # Inform the caller
1143 except ( AttributeError, TypeError ):
1144 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001145 return None
Jon Halle401b092015-09-23 13:34:24 -07001146 except Exception:
1147 main.log.exception( self.name + ": Uncaught exception!" )
1148 main.cleanup()
1149 main.exit()
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001150
GlennRC073e8bc2015-10-27 17:11:28 -07001151 def addFlow( self,
1152 deviceId,
1153 appId=0,
1154 ingressPort="",
1155 egressPort="",
1156 ethType="",
1157 ethSrc="",
1158 ethDst="",
1159 vlan="",
1160 ipProto="",
1161 ipSrc=(),
1162 ipDst=(),
1163 tcpSrc="",
1164 tcpDst="",
GlennRC956ea742015-11-05 16:14:15 -08001165 udpDst="",
1166 udpSrc="",
1167 mpls="",
GlennRC073e8bc2015-10-27 17:11:28 -07001168 ip="DEFAULT",
1169 port="DEFAULT",
1170 debug=False ):
1171 """
1172 Description:
1173 Creates a single flow in the specified device
1174 Required:
1175 * deviceId: id of the device
1176 Optional:
1177 * ingressPort: port ingress device
1178 * egressPort: port of egress device
1179 * ethType: specify ethType
1180 * ethSrc: specify ethSrc ( i.e. src mac addr )
1181 * ethDst: specify ethDst ( i.e. dst mac addr )
1182 * ipProto: specify ip protocol
1183 * ipSrc: specify ip source address with mask eg. ip#/24
1184 as a tuple (type, ip#)
1185 * ipDst: specify ip destination address eg. ip#/24
1186 as a tuple (type, ip#)
1187 * tcpSrc: specify tcp source port
1188 * tcpDst: specify tcp destination port
1189 Returns:
1190 Returns main.TRUE for successful requests; Returns main.FALSE
1191 if error on requests;
1192 Returns None for exceptions
1193 NOTE:
1194 The ip and port option are for the requests input's ip and port
1195 of the ONOS node
1196 """
suibin zhangd0f09b32016-03-29 00:57:57 -07001197
GlennRC073e8bc2015-10-27 17:11:28 -07001198 try:
1199 flowJson = { "priority":100,
1200 "isPermanent":"true",
1201 "timeout":0,
1202 "deviceId":deviceId,
1203 "treatment":{"instructions":[]},
1204 "selector": {"criteria":[]}}
1205 if appId:
1206 flowJson[ "appId" ] = appId
1207 if egressPort:
1208 flowJson[ 'treatment' ][ 'instructions' ].append( {
1209 "type":"OUTPUT",
1210 "port":egressPort } )
1211 if ingressPort:
1212 flowJson[ 'selector' ][ 'criteria' ].append( {
1213 "type":"IN_PORT",
1214 "port":ingressPort } )
1215 if ethType:
1216 flowJson[ 'selector' ][ 'criteria' ].append( {
1217 "type":"ETH_TYPE",
1218 "ethType":ethType } )
1219 if ethSrc:
1220 flowJson[ 'selector' ][ 'criteria' ].append( {
1221 "type":"ETH_SRC",
1222 "mac":ethSrc } )
1223 if ethDst:
1224 flowJson[ 'selector' ][ 'criteria' ].append( {
1225 "type":"ETH_DST",
1226 "mac":ethDst } )
1227 if vlan:
1228 flowJson[ 'selector' ][ 'criteria' ].append( {
1229 "type":"VLAN_VID",
1230 "vlanId":vlan } )
GlennRC956ea742015-11-05 16:14:15 -08001231 if mpls:
1232 flowJson[ 'selector' ][ 'criteria' ].append( {
1233 "type":"MPLS_LABEL",
1234 "label":mpls } )
GlennRC073e8bc2015-10-27 17:11:28 -07001235 if ipSrc:
1236 flowJson[ 'selector' ][ 'criteria' ].append( {
1237 "type":ipSrc[0],
1238 "ip":ipSrc[1] } )
1239 if ipDst:
1240 flowJson[ 'selector' ][ 'criteria' ].append( {
1241 "type":ipDst[0],
1242 "ip":ipDst[1] } )
1243 if tcpSrc:
1244 flowJson[ 'selector' ][ 'criteria' ].append( {
1245 "type":"TCP_SRC",
1246 "tcpPort": tcpSrc } )
1247 if tcpDst:
1248 flowJson[ 'selector' ][ 'criteria' ].append( {
1249 "type":"TCP_DST",
1250 "tcpPort": tcpDst } )
GlennRC956ea742015-11-05 16:14:15 -08001251 if udpSrc:
1252 flowJson[ 'selector' ][ 'criteria' ].append( {
1253 "type":"UDP_SRC",
1254 "udpPort": udpSrc } )
1255 if udpDst:
1256 flowJson[ 'selector' ][ 'criteria' ].append( {
1257 "type":"UDP_DST",
1258 "udpPort": udpDst } )
GlennRC073e8bc2015-10-27 17:11:28 -07001259 if ipProto:
1260 flowJson[ 'selector' ][ 'criteria' ].append( {
1261 "type":"IP_PROTO",
1262 "protocol": ipProto } )
1263
1264 return self.sendFlow( deviceId=deviceId, flowJson=flowJson, debug=debug )
1265
1266 except ( AttributeError, TypeError ):
1267 main.log.exception( self.name + ": Object not as expected" )
1268 return None
1269 except Exception:
1270 main.log.exception( self.name + ": Uncaught exception!" )
1271 main.cleanup()
1272 main.exit()
1273
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001274 def removeFlow( self, deviceId, flowId,
1275 ip="DEFAULT", port="DEFAULT" ):
1276 """
1277 Description:
1278 Remove specific device flow
1279 Required:
1280 str deviceId - id of the device
1281 str flowId - id of the flow
1282 Return:
1283 Returns main.TRUE if successfully deletes flows, otherwise
1284 Returns main.FALSE, Returns None on error
1285 """
1286 try:
1287 output = None
1288 if ip == "DEFAULT":
1289 main.log.warn( "No ip given, reverting to ip from topo file" )
1290 ip = self.ip_address
1291 if port == "DEFAULT":
1292 main.log.warn( "No port given, reverting to port " +
1293 "from topo file" )
1294 port = self.port
1295 # NOTE: REST url requires the intent id to be in decimal form
1296 query = "/" + str( deviceId ) + "/" + str( int( flowId ) )
1297 response = self.send( ip,
1298 port,
1299 method="DELETE",
1300 url="/flows" + query )
1301 if response:
1302 if 200 <= response[ 0 ] <= 299:
1303 return main.TRUE
1304 else:
1305 main.log.error( "Error with REST request, response was: " +
1306 str( response ) )
1307 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -07001308 except ( AttributeError, TypeError ):
1309 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001310 return None
Jon Halle401b092015-09-23 13:34:24 -07001311 except Exception:
1312 main.log.exception( self.name + ": Uncaught exception!" )
1313 main.cleanup()
1314 main.exit()
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001315
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001316 def checkFlowsState( self , ip="DEFAULT", port="DEFAULT" ):
1317 """
1318 Description:
1319 Check if all the current flows are in ADDED state
1320 Return:
1321 returnValue - Returns main.TRUE only if all flows are in
1322 return main.FALSE otherwise;
1323 Returns None for exception
1324 """
1325 try:
1326 tempFlows = json.loads( self.flows( ip=ip, port=port ) )
1327 returnValue = main.TRUE
suibin zhangd0f09b32016-03-29 00:57:57 -07001328 numPending = 0
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001329 for flow in tempFlows:
1330 if flow.get( 'state' ) != 'ADDED':
suibin zhangd0f09b32016-03-29 00:57:57 -07001331 '''
1332 main.log.debug( self.name + ": flow Id: " +
1333 str( flow.get( 'id' ) ) +
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001334 " | state:" +
1335 str( flow.get( 'state' ) ) )
suibin zhangd0f09b32016-03-29 00:57:57 -07001336 '''
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001337 returnValue = main.FALSE
suibin zhangd0f09b32016-03-29 00:57:57 -07001338 numPending += 1
suibin zhang37e4aa92016-03-30 16:16:16 -07001339 main.log.info("Number of PENDING flows are: " + str(numPending))
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001340 return returnValue
Jon Halle401b092015-09-23 13:34:24 -07001341 except ( AttributeError, TypeError ):
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001342 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001343 return None
1344 except Exception:
1345 main.log.exception( self.name + ": Uncaught exception!" )
1346 main.cleanup()
1347 main.exit()
Jon Hall66e001c2015-11-12 09:45:10 -08001348
suibin zhangd0f09b32016-03-29 00:57:57 -07001349 def addFlow( self,
1350 deviceId,
1351 appId=0,
1352 ingressPort="",
1353 egressPort="",
1354 ethType="",
1355 ethSrc="",
1356 ethDst="",
1357 vlan="",
1358 ipProto="",
1359 ipSrc=(),
1360 ipDst=(),
1361 tcpSrc="",
1362 tcpDst="",
1363 udpDst="",
1364 udpSrc="",
1365 mpls="",
1366 ip="DEFAULT",
1367 port="DEFAULT",
1368 debug=False ):
1369
1370 """
1371 Description:
1372 Creates a single flow in the specified device
1373 Required:
1374 * deviceId: id of the device
1375 Optional:
1376 * ingressPort: port ingress device
1377 * egressPort: port of egress device
1378 * ethType: specify ethType
1379 * ethSrc: specify ethSrc ( i.e. src mac addr )
1380 * ethDst: specify ethDst ( i.e. dst mac addr )
1381 * ipProto: specify ip protocol
1382 * ipSrc: specify ip source address with mask eg. ip#/24
1383 as a tuple (type, ip#)
1384 * ipDst: specify ip destination address eg. ip#/24
1385 as a tuple (type, ip#)
1386 * tcpSrc: specify tcp source port
1387 * tcpDst: specify tcp destination port
1388 Returns:
1389 Returns main.TRUE for successful requests; Returns main.FALSE
1390 if error on requests;
1391 Returns None for exceptions
1392 NOTE:
1393 The ip and port option are for the requests input's ip and port
1394 of the ONOS node
1395 """
1396 try:
1397 flowJson = { "priority":100,
1398 "isPermanent":"true",
1399 "timeout":0,
1400 "deviceId":deviceId,
1401 "treatment":{"instructions":[]},
1402 "selector": {"criteria":[]}}
1403 if appId:
1404 flowJson[ "appId" ] = appId
1405 if egressPort:
1406 flowJson[ 'treatment' ][ 'instructions' ].append( {
1407 "type":"OUTPUT",
1408 "port":egressPort } )
1409 if ingressPort:
1410 flowJson[ 'selector' ][ 'criteria' ].append( {
1411 "type":"IN_PORT",
1412 "port":ingressPort } )
1413 if ethType:
1414 flowJson[ 'selector' ][ 'criteria' ].append( {
1415 "type":"ETH_TYPE",
1416 "ethType":ethType } )
1417 if ethSrc:
1418 flowJson[ 'selector' ][ 'criteria' ].append( {
1419 "type":"ETH_SRC",
1420 "mac":ethSrc } )
1421 if ethDst:
1422 flowJson[ 'selector' ][ 'criteria' ].append( {
1423 "type":"ETH_DST",
1424 "mac":ethDst } )
1425 if vlan:
1426 flowJson[ 'selector' ][ 'criteria' ].append( {
1427 "type":"VLAN_VID",
1428 "vlanId":vlan } )
1429 if mpls:
1430 flowJson[ 'selector' ][ 'criteria' ].append( {
1431 "type":"MPLS_LABEL",
1432 "label":mpls } )
1433 if ipSrc:
1434 flowJson[ 'selector' ][ 'criteria' ].append( {
1435 "type":ipSrc[0],
1436 "ip":ipSrc[1] } )
1437 if ipDst:
1438 flowJson[ 'selector' ][ 'criteria' ].append( {
1439 "type":ipDst[0],
1440 "ip":ipDst[1] } )
1441 if tcpSrc:
1442 flowJson[ 'selector' ][ 'criteria' ].append( {
1443 "type":"TCP_SRC",
1444 "tcpPort": tcpSrc } )
1445 if tcpDst:
1446 flowJson[ 'selector' ][ 'criteria' ].append( {
1447 "type":"TCP_DST",
1448 "tcpPort": tcpDst } )
1449 if udpSrc:
1450 flowJson[ 'selector' ][ 'criteria' ].append( {
1451 "type":"UDP_SRC",
1452 "udpPort": udpSrc } )
1453 if udpDst:
1454 flowJson[ 'selector' ][ 'criteria' ].append( {
1455 "type":"UDP_DST",
1456 "udpPort": udpDst } )
1457 if ipProto:
1458 flowJson[ 'selector' ][ 'criteria' ].append( {
1459 "type":"IP_PROTO",
1460 "protocol": ipProto } )
1461
1462 return self.sendFlow( deviceId=deviceId, flowJson=flowJson, debug=debug )
1463
1464 except ( AttributeError, TypeError ):
1465 main.log.exception( self.name + ": Object not as expected" )
1466 return None
1467 except Exception:
1468 main.log.exception( self.name + ": Uncaught exception!" )
1469 main.cleanup()
1470 main.exit()
1471
1472 def removeFlow( self, deviceId, flowId,
1473 ip="DEFAULT", port="DEFAULT" ):
1474 """
1475 Description:
1476 Remove specific device flow
1477 Required:
1478 str deviceId - id of the device
1479 str flowId - id of the flow
1480 Return:
1481 Returns main.TRUE if successfully deletes flows, otherwise
1482 Returns main.FALSE, Returns None on error
1483 """
1484 try:
1485 output = None
1486 if ip == "DEFAULT":
1487 main.log.warn( "No ip given, reverting to ip from topo file" )
1488 ip = self.ip_address
1489 if port == "DEFAULT":
1490 main.log.warn( "No port given, reverting to port " +
1491 "from topo file" )
1492 port = self.port
1493 # NOTE: REST url requires the intent id to be in decimal form
1494 query = "/" + str( deviceId ) + "/" + str( int( flowId ) )
1495 response = self.send( ip,
1496 port,
1497 method="DELETE",
1498 url="/flows" + query )
1499 if response:
1500 if 200 <= response[ 0 ] <= 299:
1501 return main.TRUE
1502 else:
1503 main.log.error( "Error with REST request, response was: " +
1504 str( response ) )
1505 return main.FALSE
1506 except ( AttributeError, TypeError ):
1507 main.log.exception( self.name + ": Object not as expected" )
1508 return None
1509 except Exception:
1510 main.log.exception( self.name + ": Uncaught exception!" )
1511 main.cleanup()
1512 main.exit()
1513
1514 def createFlowBatch( self,
1515 numSw = 1,
suibin zhanga82fe3f2016-03-29 11:26:21 -07001516 swIndex = 1,
1517 batchSize = 1,
suibin zhangd0f09b32016-03-29 00:57:57 -07001518 batchIndex = 1,
1519 deviceIdpreFix = "of:",
1520 appId=0,
1521 deviceID="",
1522 ingressPort="",
1523 egressPort="",
1524 ethType="",
1525 ethSrc="",
1526 ethDst="",
1527 vlan="",
1528 ipProto="",
1529 ipSrc=(),
1530 ipDst=(),
1531 tcpSrc="",
1532 tcpDst="",
1533 udpDst="",
1534 udpSrc="",
1535 mpls="",
1536 ip="DEFAULT",
1537 port="DEFAULT",
1538 debug=False ):
1539 """
1540 Description:
1541 Creates a single flow in the specified device
1542 Required:
1543 * deviceId: id of the device
1544 Optional:
1545 * ingressPort: port ingress device
1546 * egressPort: port of egress device
1547 * ethType: specify ethType
1548 * ethSrc: specify ethSrc ( i.e. src mac addr )
1549 * ethDst: specify ethDst ( i.e. dst mac addr )
1550 * ipProto: specify ip protocol
1551 * ipSrc: specify ip source address with mask eg. ip#/24
1552 as a tuple (type, ip#)
1553 * ipDst: specify ip destination address eg. ip#/24
1554 as a tuple (type, ip#)
1555 * tcpSrc: specify tcp source port
1556 * tcpDst: specify tcp destination port
1557 Returns:
1558 Returns main.TRUE for successful requests; Returns main.FALSE
1559 if error on requests;
1560 Returns None for exceptions
1561 NOTE:
1562 The ip and port option are for the requests input's ip and port
1563 of the ONOS node
1564 """
1565 from pprint import pprint
1566
1567 flowJsonList = []
1568 flowJsonBatch = {"flows":flowJsonList}
suibin zhanga82fe3f2016-03-29 11:26:21 -07001569 dev = swIndex
suibin zhangd0f09b32016-03-29 00:57:57 -07001570
suibin zhanga82fe3f2016-03-29 11:26:21 -07001571 for fl in range(1, batchSize + 1):
1572 flowJson = { "priority":100,
suibin zhangd0f09b32016-03-29 00:57:57 -07001573 "deviceId":"",
1574 "isPermanent":"true",
1575 "timeout":0,
1576 "treatment":{"instructions":[]},
1577 "selector": {"criteria":[]}}
1578
suibin zhang5c735ca2016-03-30 16:01:06 -07001579 #main.log.info("fl: " + str(fl))
suibin zhanga82fe3f2016-03-29 11:26:21 -07001580 if dev <= numSw:
1581 deviceId = deviceIdpreFix + "{0:0{1}x}".format(dev,16)
1582 #print deviceId
1583 flowJson['deviceId'] = deviceId
1584 dev += 1
1585 else:
1586 dev = 1
suibin zhangd0f09b32016-03-29 00:57:57 -07001587 deviceId = deviceIdpreFix + "{0:0{1}x}".format(dev,16)
1588 #print deviceId
1589 flowJson['deviceId'] = deviceId
suibin zhangff4abfe2016-03-29 11:52:08 -07001590 dev += 1
suibin zhangd0f09b32016-03-29 00:57:57 -07001591
1592 # ethSrc starts with "0"; ethDst starts with "1"
1593 # 3 Hex digit of device number; 4 digits of batch index number; 4 digits of batch size
suibin zhanga82fe3f2016-03-29 11:26:21 -07001594 ethS = "{0:0{1}x}".format(dev,4) + "{0:0{1}x}".format(batchIndex,4) + "{0:0{1}x}".format(fl,4)
1595 ethSrc = ':'.join(ethS[i:i+2] for i in range(0,len(ethS),2))
1596 ethD = "1" + "{0:0{1}x}".format(dev,3) + "{0:0{1}x}".format(batchIndex,4) + "{0:0{1}x}".format(fl,4)
1597 ethDst = ':'.join(ethD[i:i+2] for i in range(0,len(ethD),2))
suibin zhangd0f09b32016-03-29 00:57:57 -07001598
suibin zhanga82fe3f2016-03-29 11:26:21 -07001599 if appId:
1600 flowJson[ "appId" ] = appId
suibin zhangd0f09b32016-03-29 00:57:57 -07001601
suibin zhanga82fe3f2016-03-29 11:26:21 -07001602 if egressPort:
1603 flowJson[ 'treatment' ][ 'instructions' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001604 "type":"OUTPUT",
1605 "port":egressPort } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001606 if ingressPort:
1607 flowJson[ 'selector' ][ 'criteria' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001608 "type":"IN_PORT",
1609 "port":ingressPort } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001610 if ethType:
1611 flowJson[ 'selector' ][ 'criteria' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001612 "type":"ETH_TYPE",
1613 "ethType":ethType } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001614 if ethSrc:
1615 flowJson[ 'selector' ][ 'criteria' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001616 "type":"ETH_SRC",
1617 "mac":ethSrc } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001618 if ethDst:
1619 flowJson[ 'selector' ][ 'criteria' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001620 "type":"ETH_DST",
1621 "mac":ethDst } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001622 if vlan:
1623 flowJson[ 'selector' ][ 'criteria' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001624 "type":"VLAN_VID",
1625 "vlanId":vlan } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001626 if mpls:
1627 flowJson[ 'selector' ][ 'criteria' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001628 "type":"MPLS_LABEL",
1629 "label":mpls } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001630 if ipSrc:
1631 flowJson[ 'selector' ][ 'criteria' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001632 "type":ipSrc[0],
1633 "ip":ipSrc[1] } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001634 if ipDst:
1635 flowJson[ 'selector' ][ 'criteria' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001636 "type":ipDst[0],
1637 "ip":ipDst[1] } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001638 if tcpSrc:
1639 flowJson[ 'selector' ][ 'criteria' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001640 "type":"TCP_SRC",
1641 "tcpPort": tcpSrc } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001642 if tcpDst:
1643 flowJson[ 'selector' ][ 'criteria' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001644 "type":"TCP_DST",
1645 "tcpPort": tcpDst } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001646 if udpSrc:
1647 flowJson[ 'selector' ][ 'criteria' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001648 "type":"UDP_SRC",
1649 "udpPort": udpSrc } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001650 if udpDst:
1651 flowJson[ 'selector' ][ 'criteria' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001652 "type":"UDP_DST",
1653 "udpPort": udpDst } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001654 if ipProto:
1655 flowJson[ 'selector' ][ 'criteria' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001656 "type":"IP_PROTO",
1657 "protocol": ipProto } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001658 #pprint(flowJson)
1659 flowJsonList.append(flowJson)
suibin zhangd0f09b32016-03-29 00:57:57 -07001660
suibin zhanga82fe3f2016-03-29 11:26:21 -07001661 main.log.info("Number of flows in batch: " + str( len(flowJsonList) ) )
suibin zhangd0f09b32016-03-29 00:57:57 -07001662 flowJsonBatch['flows'] = flowJsonList
suibin zhang570cb452016-03-29 19:03:15 -07001663 #pprint(flowJsonBatch)
suibin zhangd0f09b32016-03-29 00:57:57 -07001664
1665 return flowJsonBatch
1666
1667 def sendFlowBatch( self, batch={}, ip="DEFAULT", port="DEFAULT", debug=False ):
1668 """
1669 Description:
1670 Sends a single flow to the specified device. This function exists
1671 so you can bypass the addFLow driver and send your own custom flow.
1672 Required:
1673 * The flow in json
1674 * the device id to add the flow to
1675 Returns:
1676 Returns main.TRUE for successful requests; Returns main.FALSE
1677 if error on requests;
1678 Returns None for exceptions
1679 NOTE:
1680 The ip and port option are for the requests input's ip and port
1681 of the ONOS node
1682 """
1683 import time
1684
1685 try:
1686 if debug: main.log.debug( "Adding flow: " + self.pprint( batch ) )
1687 output = None
1688 if ip == "DEFAULT":
1689 main.log.warn( "No ip given, reverting to ip from topo file" )
1690 ip = self.ip_address
1691 if port == "DEFAULT":
1692 main.log.warn( "No port given, reverting to port " +
1693 "from topo file" )
1694 port = self.port
1695 url = "/flows/"
1696 response = self.send( ip,
1697 port,
1698 method="POST",
1699 url=url,
1700 data=json.dumps( batch ) )
1701 #main.log.info("Post response is: ", str(response[0]))
1702 if response[0] == 200:
1703 main.log.info( self.name + ": Successfully POST flow" )
suibin zhang570cb452016-03-29 19:03:15 -07001704 return main.TRUE, response
suibin zhangd0f09b32016-03-29 00:57:57 -07001705 else:
1706 main.log.error( "Error with REST request, response was: " +
1707 str( response ) )
1708 return main.FALSE
1709 except NotImplementedError as e:
1710 raise e # Inform the caller
1711 except ( AttributeError, TypeError ):
1712 main.log.exception( self.name + ": Object not as expected" )
1713 return None
1714 except Exception:
1715 main.log.exception( self.name + ": Uncaught exception!" )
1716 main.cleanup()
1717 main.exit()
1718
suibin zhanga5875da2016-04-02 20:54:50 -07001719 def sendFlowBatchQueue(self, q=Queue(), ip="DEFAULT", port="DEFAULT", debug=False):
1720 while True:
1721 item = q.get()
1722 self.sendFlowBatch(batch = item)
1723 q.task_done()
1724
suibin zhangd0f09b32016-03-29 00:57:57 -07001725 def removeFlowBatch( self, batch={},
1726 ip="DEFAULT", port="DEFAULT" ):
1727 """
1728 Description:
1729 Remove a batch of flows
1730 Required:
1731 flow batch
1732 Return:
1733 Returns main.TRUE if successfully deletes flows, otherwise
1734 Returns main.FALSE, Returns None on error
1735 """
1736 try:
1737 output = None
1738 if ip == "DEFAULT":
1739 main.log.warn( "No ip given, reverting to ip from topo file" )
1740 ip = self.ip_address
1741 if port == "DEFAULT":
1742 main.log.warn( "No port given, reverting to port " +
1743 "from topo file" )
1744 port = self.port
1745 # NOTE: REST url requires the intent id to be in decimal form
1746
1747 response = self.send( ip,
1748 port,
1749 method="DELETE",
suibin zhang570cb452016-03-29 19:03:15 -07001750 url="/flows/",
1751 data = json.dumps(batch) )
suibin zhangd0f09b32016-03-29 00:57:57 -07001752 if response:
1753 if 200 <= response[ 0 ] <= 299:
1754 return main.TRUE
1755 else:
1756 main.log.error( "Error with REST request, response was: " +
1757 str( response ) )
1758 return main.FALSE
1759 except ( AttributeError, TypeError ):
1760 main.log.exception( self.name + ": Object not as expected" )
1761 return None
1762 except Exception:
1763 main.log.exception( self.name + ": Uncaught exception!" )
1764 main.cleanup()
1765 main.exit()
1766
Jon Hall66e001c2015-11-12 09:45:10 -08001767 def getNetCfg( self, ip="DEFAULT", port="DEFAULT",
1768 subjectClass=None, subjectKey=None, configKey=None ):
1769 """
1770 Description:
1771 Get a json object with the ONOS network configurations
1772 Returns:
1773 A json object containing the network configuration in
1774 ONOS; Returns main.FALSE if error on requests;
1775 Returns None for exception
1776 """
1777 try:
1778 output = None
1779 if ip == "DEFAULT":
1780 main.log.warn( "No ip given, reverting to ip from topo file" )
1781 ip = self.ip_address
1782 if port == "DEFAULT":
1783 main.log.warn( "No port given, reverting to port " +
1784 "from topo file" )
1785 port = self.port
1786 url = "/network/configuration"
1787 if subjectClass:
1788 url += "/" + subjectClass
1789 if subjectKey:
1790 url += "/" + subjectKey
1791 if configKey:
1792 url += "/" + configKey
1793 response = self.send( ip, port, url=url )
1794 if response:
1795 if 200 <= response[ 0 ] <= 299:
1796 output = response[ 1 ]
1797 a = json.loads( output )
1798 b = json.dumps( a )
1799 return b
1800 elif response[ 0 ] == 404:
1801 main.log.error( "Requested configuration doesn't exist: " +
1802 str( response ) )
1803 return {}
1804 else:
1805 main.log.error( "Error with REST request, response was: " +
1806 str( response ) )
1807 return main.FALSE
1808 except ( AttributeError, TypeError ):
1809 main.log.exception( self.name + ": Object not as expected" )
1810 return None
1811 except Exception:
1812 main.log.exception( self.name + ": Uncaught exception!" )
1813 main.cleanup()
1814 main.exit()
1815
1816 def setNetCfg( self, cfgJson, ip="DEFAULT", port="DEFAULT",
1817 subjectClass=None, subjectKey=None, configKey=None ):
1818 """
1819 Description:
1820 Set a json object with the ONOS network configurations
1821 Returns:
1822 Returns main.TRUE for successful requests; Returns main.FALSE
1823 if error on requests;
1824 Returns None for exceptions
1825
1826 """
1827 try:
1828 output = None
1829 if ip == "DEFAULT":
1830 main.log.warn( "No ip given, reverting to ip from topo file" )
1831 ip = self.ip_address
1832 if port == "DEFAULT":
1833 main.log.warn( "No port given, reverting to port " +
1834 "from topo file" )
1835 port = self.port
1836 url = "/network/configuration"
1837 if subjectClass:
1838 url += "/" + subjectClass
1839 if subjectKey:
1840 url += "/" + subjectKey
1841 if configKey:
1842 url += "/" + configKey
1843 response = self.send( ip, port,
1844 method="POST",
1845 url=url,
1846 data=json.dumps( cfgJson ) )
1847 if response:
1848 if 200 <= response[ 0 ] <= 299:
1849 main.log.info( self.name + ": Successfully POST cfg" )
1850 return main.TRUE
1851 else:
1852 main.log.error( "Error with REST request, response was: " +
1853 str( response ) )
1854 return main.FALSE
1855 except ( AttributeError, TypeError ):
1856 main.log.exception( self.name + ": Object not as expected" )
1857 return None
1858 except Exception:
1859 main.log.exception( self.name + ": Uncaught exception!" )
1860 main.cleanup()
1861 main.exit()
1862
1863 def removeNetCfg( self, ip="DEFAULT", port="DEFAULT",
1864 subjectClass=None, subjectKey=None, configKey=None ):
1865 """
1866 Description:
1867 Remove a json object from the ONOS network configurations
1868 Returns:
1869 Returns main.TRUE for successful requests; Returns main.FALSE
1870 if error on requests;
1871 Returns None for exceptions
1872
1873 """
1874 try:
1875 output = None
1876 if ip == "DEFAULT":
1877 main.log.warn( "No ip given, reverting to ip from topo file" )
1878 ip = self.ip_address
1879 if port == "DEFAULT":
1880 main.log.warn( "No port given, reverting to port " +
1881 "from topo file" )
1882 port = self.port
1883 url = "/network/configuration"
1884 if subjectClass:
1885 url += "/" + subjectClass
1886 if subjectKey:
1887 url += "/" + subjectKey
1888 if configKey:
1889 url += "/" + configKey
1890 response = self.send( ip, port,
1891 method="DELETE",
1892 url=url )
1893 if response:
1894 if 200 <= response[ 0 ] <= 299:
1895 main.log.info( self.name + ": Successfully delete cfg" )
1896 return main.TRUE
1897 else:
1898 main.log.error( "Error with REST request, response was: " +
1899 str( response ) )
1900 return main.FALSE
1901 except ( AttributeError, TypeError ):
1902 main.log.exception( self.name + ": Object not as expected" )
1903 return None
1904 except Exception:
1905 main.log.exception( self.name + ": Uncaught exception!" )
1906 main.cleanup()
1907 main.exit()