blob: 0d335c126771f7181b0bd88ac81e4eee7388cf8b [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
Jon Hallfc915882015-07-14 13:33:17 -070024
Jon Hallfc915882015-07-14 13:33:17 -070025from drivers.common.api.controllerdriver import Controller
26
27
28class OnosRestDriver( Controller ):
29
30 def __init__( self ):
Jon Hallf7234882015-08-28 13:16:31 -070031 self.pwd = None
32 self.user_name = "user"
Jon Hallfc915882015-07-14 13:33:17 -070033 super( Controller, self ).__init__()
34 self.ip_address = "localhost"
35 self.port = "8080"
Jon Halle401b092015-09-23 13:34:24 -070036 self.wrapped = sys.modules[ __name__ ]
Jon Hallfc915882015-07-14 13:33:17 -070037
38 def connect( self, **connectargs ):
39 try:
40 for key in connectargs:
41 vars( self )[ key ] = connectargs[ key ]
42 self.name = self.options[ 'name' ]
43 except Exception as e:
44 main.log.exception( e )
45 try:
46 if os.getenv( str( self.ip_address ) ) != None:
47 self.ip_address = os.getenv( str( self.ip_address ) )
48 else:
kelvin-onlab03eb88d2015-07-22 10:29:02 -070049 main.log.info( self.name + ": ip set to " + self.ip_address )
Jon Hallfc915882015-07-14 13:33:17 -070050 except KeyError:
51 main.log.info( "Invalid host name," +
52 "defaulting to 'localhost' instead" )
53 self.ip_address = 'localhost'
54 except Exception as inst:
55 main.log.error( "Uncaught exception: " + str( inst ) )
56
57 self.handle = super( OnosRestDriver, self ).connect()
58 return self.handle
59
Jon Halle401b092015-09-23 13:34:24 -070060 def pprint( self, jsonObject ):
61 """
62 Pretty Prints a json object
63
64 arguments:
65 jsonObject - a parsed json object
66 returns:
67 A formatted string for printing or None on error
68 """
69 try:
70 if isinstance( jsonObject, str ):
71 jsonObject = json.loads( jsonObject )
72 return json.dumps( jsonObject, sort_keys=True,
73 indent=4, separators=(',', ': '))
74 except ( TypeError, ValueError ):
75 main.log.exception( "Error parsing jsonObject" )
76 return None
77
Jon Hallfc915882015-07-14 13:33:17 -070078 def send( self, ip, port, url, base="/onos/v1", method="GET",
Jon Hallf7234882015-08-28 13:16:31 -070079 query=None, data=None, debug=False ):
Jon Hallfc915882015-07-14 13:33:17 -070080 """
81 Arguments:
82 str ip: ONOS IP Address
83 str port: ONOS REST Port
84 str url: ONOS REST url path.
85 NOTE that this is is only the relative path. IE "/devices"
86 str base: The base url for the given REST api. Applications could
87 potentially have their own base url
88 str method: HTTP method type
kelvin-onlab03eb88d2015-07-22 10:29:02 -070089 dict query: Dictionary to be sent in the query string for
Jon Hallfc915882015-07-14 13:33:17 -070090 the request
91 dict data: Dictionary to be sent in the body of the request
92 """
93 # TODO: Authentication - simple http (user,pass) tuple
94 # TODO: should we maybe just pass kwargs straight to response?
95 # TODO: Do we need to allow for other protocols besides http?
96 # ANSWER: Not yet, but potentially https with certificates
97 try:
98 path = "http://" + str( ip ) + ":" + str( port ) + base + url
Jon Hallf7234882015-08-28 13:16:31 -070099 if self.user_name and self.pwd:
suibin zhangeb121c02015-11-04 12:06:38 -0800100 main.log.info("user/passwd is: " + self.user_name + "/" + self.pwd)
Jon Hallf7234882015-08-28 13:16:31 -0700101 auth = (self.user_name, self.pwd)
102 else:
103 auth=None
Jon Hallfc915882015-07-14 13:33:17 -0700104 main.log.info( "Sending request " + path + " using " +
105 method.upper() + " method." )
106 response = requests.request( method.upper(),
107 path,
108 params=query,
Jon Hallf7234882015-08-28 13:16:31 -0700109 data=data,
110 auth=auth )
111 if debug:
112 main.log.debug( response )
Jon Hallfc915882015-07-14 13:33:17 -0700113 return ( response.status_code, response.text.encode( 'utf8' ) )
114 except requests.exceptions:
115 main.log.exception( "Error sending request." )
116 return None
Jon Halle401b092015-09-23 13:34:24 -0700117 except Exception:
118 main.log.exception( self.name + ": Uncaught exception!" )
119 main.cleanup()
120 main.exit()
Jon Hallfc915882015-07-14 13:33:17 -0700121
122 def intents( self, ip="DEFAULT", port="DEFAULT" ):
123 """
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700124 Description:
125 Gets a list of dictionary of all intents in the system
126 Returns:
127 A list of dictionary of intents in string type to match the cli
128 version for now; Returns main.FALSE if error on request;
129 Returns None for exception
Jon Hallfc915882015-07-14 13:33:17 -0700130 """
131 try:
132 output = None
133 if ip == "DEFAULT":
134 main.log.warn( "No ip given, reverting to ip from topo file" )
135 ip = self.ip_address
136 if port == "DEFAULT":
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700137 main.log.warn( "No port given, reverting to port " +
138 "from topo file" )
Jon Hallfc915882015-07-14 13:33:17 -0700139 port = self.port
140 response = self.send( ip, port, url="/intents" )
141 if response:
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700142 if 200 <= response[ 0 ] <= 299:
143 output = response[ 1 ]
144 a = json.loads( output ).get( 'intents' )
Jon Halle401b092015-09-23 13:34:24 -0700145 assert a is not None, "Error parsing json object"
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700146 b = json.dumps( a )
147 return b
Jon Hallfc915882015-07-14 13:33:17 -0700148 else:
149 main.log.error( "Error with REST request, response was: " +
150 str( response ) )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700151 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700152 except ( AttributeError, AssertionError, TypeError ):
153 main.log.exception( self.name + ": Object not as expected" )
Jon Hallfc915882015-07-14 13:33:17 -0700154 return None
Jon Halle401b092015-09-23 13:34:24 -0700155 except Exception:
156 main.log.exception( self.name + ": Uncaught exception!" )
157 main.cleanup()
158 main.exit()
Jon Hallfc915882015-07-14 13:33:17 -0700159
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700160 def intent( self, intentId, appId="org.onosproject.cli",
161 ip="DEFAULT", port="DEFAULT" ):
Jon Hallfc915882015-07-14 13:33:17 -0700162 """
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700163 Description:
164 Get the specific intent information of the given application ID and
165 intent ID
166 Required:
167 str intentId - Intent id in hexadecimal form
168 Optional:
169 str appId - application id of intent
170 Returns:
171 Returns an information dictionary of the given intent;
172 Returns main.FALSE if error on requests; Returns None for exception
173 NOTE:
174 The GET /intents REST api command accepts application id but the
175 api will get updated to accept application name instead
Jon Hallfc915882015-07-14 13:33:17 -0700176 """
177 try:
178 output = None
179 if ip == "DEFAULT":
180 main.log.warn( "No ip given, reverting to ip from topo file" )
181 ip = self.ip_address
182 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -0700183 main.log.warn( "No port given, reverting to port " +
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700184 "from topo file" )
Jon Hallfc915882015-07-14 13:33:17 -0700185 port = self.port
186 # NOTE: REST url requires the intent id to be in decimal form
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700187 query = "/" + str( appId ) + "/" + str( intentId )
Jon Hallfc915882015-07-14 13:33:17 -0700188 response = self.send( ip, port, url="/intents" + query )
189 if response:
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700190 if 200 <= response[ 0 ] <= 299:
191 output = response[ 1 ]
192 a = json.loads( output )
193 return a
Jon Hallfc915882015-07-14 13:33:17 -0700194 else:
195 main.log.error( "Error with REST request, response was: " +
196 str( response ) )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700197 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700198 except ( AttributeError, TypeError ):
199 main.log.exception( self.name + ": Object not as expected" )
Jon Hallfc915882015-07-14 13:33:17 -0700200 return None
Jon Halle401b092015-09-23 13:34:24 -0700201 except Exception:
202 main.log.exception( self.name + ": Uncaught exception!" )
203 main.cleanup()
204 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700205
206 def getIntentsId( self, ip="DEFAULT", port="DEFAULT" ):
207 """
208 Description:
209 Gets all intents ID using intents function
210 Returns:
211 List of intents ID;Returns None for exception; Returns None for
212 exception; Returns None for exception
213 """
214 try:
215 intentsDict = {}
216 intentsIdList = []
217 intentsDict = json.loads( self.intents( ip=ip, port=port ) )
218 for intent in intentsDict:
219 intentsIdList.append( intent.get( 'id' ) )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700220 if not intentsIdList:
221 main.log.debug( "Cannot find any intents" )
222 return main.FALSE
223 else:
224 main.log.info( "Found intents: " + str( intentsIdList ) )
225 return main.TRUE
Jon Halle401b092015-09-23 13:34:24 -0700226 except ( AttributeError, TypeError ):
227 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700228 return None
Jon Halle401b092015-09-23 13:34:24 -0700229 except Exception:
230 main.log.exception( self.name + ": Uncaught exception!" )
231 main.cleanup()
232 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700233
234 def apps( self, ip="DEFAULT", port="DEFAULT" ):
235 """
236 Description:
237 Returns all the current application installed in the system
238 Returns:
239 List of dictionary of installed application; Returns main.FALSE for
240 error on request; Returns None for exception
241 """
242 try:
243 output = None
244 if ip == "DEFAULT":
245 main.log.warn( "No ip given, reverting to ip from topo file" )
246 ip = self.ip_address
247 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -0700248 main.log.warn( "No port given, reverting to port " +
249 "from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700250 port = self.port
251 response = self.send( ip, port, url="/applications" )
252 if response:
253 if 200 <= response[ 0 ] <= 299:
254 output = response[ 1 ]
255 a = json.loads( output ).get( 'applications' )
Jon Halle401b092015-09-23 13:34:24 -0700256 assert a is not None, "Error parsing json object"
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700257 b = json.dumps( a )
258 return b
259 else:
260 main.log.error( "Error with REST request, response was: " +
261 str( response ) )
262 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700263 except ( AttributeError, AssertionError, TypeError ):
264 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700265 return None
Jon Halle401b092015-09-23 13:34:24 -0700266 except Exception:
267 main.log.exception( self.name + ": Uncaught exception!" )
268 main.cleanup()
269 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700270
271 def activateApp( self, appName, ip="DEFAULT", port="DEFAULT", check=True ):
272 """
273 Decription:
274 Activate an app that is already installed in ONOS
275 Optional:
276 bool check - If check is True, method will check the status
277 of the app after the command is issued
278 Returns:
279 Returns main.TRUE if the command was successfully or main.FALSE
280 if the REST responded with an error or given incorrect input;
281 Returns None for exception
282
283 """
284 try:
285 output = None
286 if ip == "DEFAULT":
287 main.log.warn( "No ip given, reverting to ip from topo file" )
288 ip = self.ip_address
289 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -0700290 main.log.warn( "No port given, reverting to port " +
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700291 "from topo file" )
292 port = self.port
293 query = "/" + str( appName ) + "/active"
294 response = self.send( ip, port, method="POST",
295 url="/applications" + query )
296 if response:
297 output = response[ 1 ]
298 app = json.loads( output )
299 if 200 <= response[ 0 ] <= 299:
300 if check:
301 if app.get( 'state' ) == 'ACTIVE':
302 main.log.info( self.name + ": " + appName +
303 " application" +
304 " is in ACTIVE state" )
305 return main.TRUE
306 else:
307 main.log.error( self.name + ": " + appName +
308 " application" + " is in " +
309 app.get( 'state' ) + " state" )
310 return main.FALSE
311 else:
312 main.log.warn( "Skipping " + appName +
313 "application check" )
314 return main.TRUE
315 else:
316 main.log.error( "Error with REST request, response was: " +
317 str( response ) )
318 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700319 except ( AttributeError, TypeError ):
320 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700321 return None
Jon Halle401b092015-09-23 13:34:24 -0700322 except Exception:
323 main.log.exception( self.name + ": Uncaught exception!" )
324 main.cleanup()
325 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700326
327 def deactivateApp( self, appName, ip="DEFAULT", port="DEFAULT",
328 check=True ):
329 """
330 Required:
331 Deactivate an app that is already activated in ONOS
332 Optional:
333 bool check - If check is True, method will check the status of the
334 app after the command is issued
335 Returns:
336 Returns main.TRUE if the command was successfully sent
337 main.FALSE if the REST responded with an error or given
338 incorrect input; Returns None for exception
339 """
340 try:
341 output = None
342 if ip == "DEFAULT":
343 main.log.warn( "No ip given, reverting to ip from topo file" )
344 ip = self.ip_address
345 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -0700346 main.log.warn( "No port given, reverting to port " +
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700347 "from topo file" )
348 port = self.port
349 query = "/" + str( appName ) + "/active"
350 response = self.send( ip, port, method="DELETE",
351 url="/applications" + query )
352 if response:
353 output = response[ 1 ]
354 app = json.loads( output )
355 if 200 <= response[ 0 ] <= 299:
356 if check:
357 if app.get( 'state' ) == 'INSTALLED':
358 main.log.info( self.name + ": " + appName +
359 " application" +
360 " is in INSTALLED state" )
361 return main.TRUE
362 else:
363 main.log.error( self.name + ": " + appName +
364 " application" + " is in " +
365 app.get( 'state' ) + " state" )
366 return main.FALSE
367 else:
368 main.log.warn( "Skipping " + appName +
369 "application check" )
370 return main.TRUE
371 else:
372 main.log.error( "Error with REST request, response was: " +
373 str( response ) )
374 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700375 except ( AttributeError, TypeError ):
376 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700377 return None
Jon Halle401b092015-09-23 13:34:24 -0700378 except Exception:
379 main.log.exception( self.name + ": Uncaught exception!" )
380 main.cleanup()
381 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700382
383 def getApp( self, appName, project="org.onosproject.", ip="DEFAULT",
384 port="DEFAULT" ):
385 """
386 Decription:
387 Gets the informaion of the given application
388 Required:
389 str name - Name of onos application
390 Returns:
391 Returns a dictionary of information ONOS application in string type;
392 Returns main.FALSE if error on requests; Returns None for exception
393 """
394 try:
395 output = None
396 if ip == "DEFAULT":
397 main.log.warn( "No ip given, reverting to ip from topo file" )
398 ip = self.ip_address
399 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -0700400 main.log.warn( "No port given, reverting to port " +
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700401 "from topo file" )
402 port = self.port
403 query = "/" + project + str( appName )
404 response = self.send( ip, port, url="/applications" + query )
405 if response:
406 if 200 <= response[ 0 ] <= 299:
407 output = response[ 1 ]
408 a = json.loads( output )
409 return a
410 else:
411 main.log.error( "Error with REST request, response was: " +
412 str( response ) )
413 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700414 except ( AttributeError, TypeError ):
415 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700416 return None
Jon Halle401b092015-09-23 13:34:24 -0700417 except Exception:
418 main.log.exception( self.name + ": Uncaught exception!" )
419 main.cleanup()
420 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700421
422 def addHostIntent( self, hostIdOne, hostIdTwo, appId='org.onosproject.cli',
423 ip="DEFAULT", port="DEFAULT" ):
424 """
425 Description:
426 Adds a host-to-host intent ( bidirectional ) by
427 specifying the two hosts.
428 Required:
429 * hostIdOne: ONOS host id for host1
430 * hostIdTwo: ONOS host id for host2
431 Optional:
432 str appId - Application name of intent identifier
433 Returns:
kelvin-onlabb50074f2015-07-27 16:18:32 -0700434 Returns main.TRUE for successful requests; Returns main.FALSE if
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700435 error on requests; Returns None for exceptions
436 """
437 try:
438 intentJson = {"two": str( hostIdTwo ),
439 "selector": {"criteria": []}, "priority": 7,
440 "treatment": {"deferred": [], "instructions": []},
441 "appId": appId, "one": str( hostIdOne ),
442 "type": "HostToHostIntent",
443 "constraints": [{"type": "LinkTypeConstraint",
444 "types": ["OPTICAL"],
445 "inclusive": 'false' }]}
446 output = None
447 if ip == "DEFAULT":
448 main.log.warn( "No ip given, reverting to ip from topo file" )
449 ip = self.ip_address
450 if port == "DEFAULT":
451 main.log.warn( "No port given, reverting to port " +
452 "from topo file" )
453 port = self.port
454 response = self.send( ip,
455 port,
456 method="POST",
457 url="/intents",
458 data=json.dumps( intentJson ) )
459 if response:
460 if 201:
461 main.log.info( self.name + ": Successfully POST host" +
462 " intent between host: " + hostIdOne +
463 " and host: " + hostIdTwo )
464 return main.TRUE
465 else:
466 main.log.error( "Error with REST request, response was: " +
467 str( response ) )
468 return main.FALSE
469
Jon Halle401b092015-09-23 13:34:24 -0700470 except ( AttributeError, TypeError ):
471 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700472 return None
Jon Halle401b092015-09-23 13:34:24 -0700473 except Exception:
474 main.log.exception( self.name + ": Uncaught exception!" )
475 main.cleanup()
476 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700477
kelvin-onlabb50074f2015-07-27 16:18:32 -0700478 def addPointIntent( self,
479 ingressDevice,
480 egressDevice,
kelvin-onlabb50074f2015-07-27 16:18:32 -0700481 appId='org.onosproject.cli',
482 ingressPort="",
483 egressPort="",
484 ethType="",
485 ethSrc="",
486 ethDst="",
487 bandwidth="",
488 lambdaAlloc=False,
489 ipProto="",
490 ipSrc="",
491 ipDst="",
492 tcpSrc="",
kelvin-onlab9b42b0a2015-08-05 14:43:58 -0700493 tcpDst="",
494 ip="DEFAULT",
495 port="DEFAULT" ):
kelvin-onlabb50074f2015-07-27 16:18:32 -0700496 """
497 Description:
498 Adds a point-to-point intent ( uni-directional ) by
499 specifying device id's and optional fields
500 Required:
501 * ingressDevice: device id of ingress device
502 * egressDevice: device id of egress device
503 Optional:
504 * ethType: specify ethType
505 * ethSrc: specify ethSrc ( i.e. src mac addr )
506 * ethDst: specify ethDst ( i.e. dst mac addr )
507 * bandwidth: specify bandwidth capacity of link (TODO)
508 * lambdaAlloc: if True, intent will allocate lambda
509 for the specified intent (TODO)
510 * ipProto: specify ip protocol
511 * ipSrc: specify ip source address with mask eg. ip#/24
512 * ipDst: specify ip destination address eg. ip#/24
513 * tcpSrc: specify tcp source port
514 * tcpDst: specify tcp destination port
515 Returns:
516 Returns main.TRUE for successful requests; Returns main.FALSE if
517 no ingress|egress port found and if error on requests;
518 Returns None for exceptions
519 NOTE:
520 The ip and port option are for the requests input's ip and port
521 of the ONOS node
522 """
523 try:
524 if "/" in ingressDevice:
525 if not ingressPort:
526 ingressPort = ingressDevice.split( "/" )[ 1 ]
527 ingressDevice = ingressDevice.split( "/" )[ 0 ]
528 else:
529 if not ingressPort:
530 main.log.debug( self.name + ": Ingress port not specified" )
531 return main.FALSE
532
533 if "/" in egressDevice:
534 if not egressPort:
535 egressPort = egressDevice.split( "/" )[ 1 ]
536 egressDevice = egressDevice.split( "/" )[ 0 ]
537 else:
538 if not egressPort:
539 main.log.debug( self.name + ": Egress port not specified" )
540 return main.FALSE
541
542 intentJson ={ "ingressPoint": { "device": ingressDevice,
543 "port": ingressPort },
544 "selector": { "criteria": [] },
545 "priority": 55,
546 "treatment": { "deferred": [],
547 "instructions": [] },
548 "egressPoint": { "device": egressDevice,
549 "port": egressPort },
550 "appId": appId,
551 "type": "PointToPointIntent",
552 "constraints": [ { "type": "LinkTypeConstraint",
553 "types": [ "OPTICAL" ],
554 "inclusive": "false" } ] }
555
556 if ethType == "IPV4":
557 intentJson[ 'selector' ][ 'criteria' ].append( {
558 "type":"ETH_TYPE",
559 "ethType":2048 } )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -0700560 elif ethType:
561 intentJson[ 'selector' ][ 'criteria' ].append( {
562 "type":"ETH_TYPE",
563 "ethType":ethType } )
564
kelvin-onlabb50074f2015-07-27 16:18:32 -0700565 if ethSrc:
566 intentJson[ 'selector' ][ 'criteria' ].append(
567 { "type":"ETH_SRC",
568 "mac":ethSrc } )
569 if ethDst:
570 intentJson[ 'selector' ][ 'criteria' ].append(
571 { "type":"ETH_DST",
572 "mac":ethDst } )
573 if ipSrc:
574 intentJson[ 'selector' ][ 'criteria' ].append(
575 { "type":"IPV4_SRC",
576 "ip":ipSrc } )
577 if ipDst:
578 intentJson[ 'selector' ][ 'criteria' ].append(
579 { "type":"IPV4_DST",
580 "ip":ipDst } )
581 if tcpSrc:
582 intentJson[ 'selector' ][ 'criteria' ].append(
583 { "type":"TCP_SRC",
584 "tcpPort": tcpSrc } )
585 if tcpDst:
586 intentJson[ 'selector' ][ 'criteria' ].append(
587 { "type":"TCP_DST",
588 "tcpPort": tcpDst } )
589 if ipProto:
590 intentJson[ 'selector' ][ 'criteria' ].append(
591 { "type":"IP_PROTO",
592 "protocol": ipProto } )
593
594 # TODO: Bandwidth and Lambda will be implemented if needed
595
596 main.log.debug( intentJson )
597
598 output = None
599 if ip == "DEFAULT":
600 main.log.warn( "No ip given, reverting to ip from topo file" )
601 ip = self.ip_address
602 if port == "DEFAULT":
603 main.log.warn( "No port given, reverting to port " +
604 "from topo file" )
605 port = self.port
606 response = self.send( ip,
607 port,
608 method="POST",
609 url="/intents",
610 data=json.dumps( intentJson ) )
611 if response:
612 if 201:
613 main.log.info( self.name + ": Successfully POST point" +
614 " intent between ingress: " + ingressDevice +
615 " and egress: " + egressDevice + " devices" )
616 return main.TRUE
617 else:
618 main.log.error( "Error with REST request, response was: " +
619 str( response ) )
620 return main.FALSE
621
Jon Halle401b092015-09-23 13:34:24 -0700622 except ( AttributeError, TypeError ):
623 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlabb50074f2015-07-27 16:18:32 -0700624 return None
Jon Halle401b092015-09-23 13:34:24 -0700625 except Exception:
626 main.log.exception( self.name + ": Uncaught exception!" )
627 main.cleanup()
628 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700629
630 def removeIntent( self, intentId, appId='org.onosproject.cli',
631 ip="DEFAULT", port="DEFAULT" ):
632 """
633 Remove intent for specified application id and intent id;
634 Returns None for exception
635 """
636 try:
637 output = None
638 if ip == "DEFAULT":
639 main.log.warn( "No ip given, reverting to ip from topo file" )
640 ip = self.ip_address
641 if port == "DEFAULT":
642 main.log.warn( "No port given, reverting to port " +
643 "from topo file" )
644 port = self.port
645 # NOTE: REST url requires the intent id to be in decimal form
646 query = "/" + str( appId ) + "/" + str( int( intentId, 16 ) )
647 response = self.send( ip,
648 port,
649 method="DELETE",
650 url="/intents" + query )
651 if response:
652 if 200 <= response[ 0 ] <= 299:
653 return main.TRUE
654 else:
655 main.log.error( "Error with REST request, response was: " +
656 str( response ) )
657 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700658 except ( AttributeError, TypeError ):
659 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700660 return None
Jon Halle401b092015-09-23 13:34:24 -0700661 except Exception:
662 main.log.exception( self.name + ": Uncaught exception!" )
663 main.cleanup()
664 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700665
666 def getIntentsId( self, ip="DEFAULT", port="DEFAULT" ):
667 """
668 Returns a list of intents id; Returns None for exception
669 """
670 try:
671 intentIdList = []
672 intentsJson = json.loads( self.intents() )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700673 for intent in intentsJson:
674 intentIdList.append( intent.get( 'id' ) )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700675 return intentIdList
Jon Halle401b092015-09-23 13:34:24 -0700676 except ( AttributeError, TypeError ):
677 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700678 return None
Jon Halle401b092015-09-23 13:34:24 -0700679 except Exception:
680 main.log.exception( self.name + ": Uncaught exception!" )
681 main.cleanup()
682 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700683
684 def removeAllIntents( self, intentIdList ='ALL',appId='org.onosproject.cli',
685 ip="DEFAULT", port="DEFAULT", delay=5 ):
686 """
687 Description:
688 Remove all the intents
689 Returns:
690 Returns main.TRUE if all intents are removed, otherwise returns
691 main.FALSE; Returns None for exception
692 """
693 try:
694 results = []
695 if intentIdList == 'ALL':
696 intentIdList = self.getIntentsId( ip=ip, port=port )
697
698 main.log.info( self.name + ": Removing intents " +
699 str( intentIdList ) )
700
701 if isinstance( intentIdList, types.ListType ):
702 for intent in intentIdList:
703 results.append( self.removeIntent( intentId=intent,
704 appId=appId,
705 ip=ip,
706 port=port ) )
707 # Check for remaining intents
708 # NOTE: Noticing some delay on Deleting the intents so i put
709 # this time out
710 import time
711 time.sleep( delay )
712 intentRemain = len( json.loads( self.intents() ) )
713 if all( result==main.TRUE for result in results ) and \
714 intentRemain == 0:
715 main.log.info( self.name + ": All intents are removed " )
716 return main.TRUE
717 else:
718 main.log.error( self.name + ": Did not removed all intents,"
719 + " there are " + str( intentRemain )
720 + " intents remaining" )
721 return main.FALSE
722 else:
723 main.log.debug( self.name + ": There is no intents ID list" )
Jon Halle401b092015-09-23 13:34:24 -0700724 except ( AttributeError, TypeError ):
725 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700726 return None
Jon Halle401b092015-09-23 13:34:24 -0700727 except Exception:
728 main.log.exception( self.name + ": Uncaught exception!" )
729 main.cleanup()
730 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700731
732 def hosts( self, ip="DEFAULT", port="DEFAULT" ):
733 """
734 Description:
735 Get a list of dictionary of all discovered hosts
736 Returns:
737 Returns a list of dictionary of information of the hosts currently
738 discovered by ONOS; Returns main.FALSE if error on requests;
739 Returns None for exception
740 """
741 try:
742 output = None
743 if ip == "DEFAULT":
744 main.log.warn( "No ip given, reverting to ip from topo file" )
745 ip = self.ip_address
746 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -0700747 main.log.warn( "No port given, reverting to port " +
748 "from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700749 port = self.port
750 response = self.send( ip, port, url="/hosts" )
751 if response:
752 if 200 <= response[ 0 ] <= 299:
753 output = response[ 1 ]
754 a = json.loads( output ).get( 'hosts' )
Jon Halle401b092015-09-23 13:34:24 -0700755 assert a is not None, "Error parsing json object"
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700756 b = json.dumps( a )
757 return b
758 else:
759 main.log.error( "Error with REST request, response was: " +
760 str( response ) )
761 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700762 except ( AttributeError, AssertionError, TypeError ):
763 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700764 return None
Jon Halle401b092015-09-23 13:34:24 -0700765 except Exception:
766 main.log.exception( self.name + ": Uncaught exception!" )
767 main.cleanup()
768 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700769
770 def getHost( self, mac, vlan="-1", ip="DEFAULT", port="DEFAULT" ):
771 """
772 Description:
773 Gets the information from the given host
774 Required:
775 str mac - MAC address of the host
776 Optional:
777 str vlan - VLAN tag of the host, defaults to -1
778 Returns:
779 Return the host id from the hosts/mac/vlan output in REST api
780 whose 'id' contains mac/vlan; Returns None for exception;
781 Returns main.FALSE if error on requests
782
783 NOTE:
784 Not sure what this function should do, any suggestion?
785 """
786 try:
787 output = None
788 if ip == "DEFAULT":
789 main.log.warn( "No ip given, reverting to ip from topo file" )
790 ip = self.ip_address
791 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -0700792 main.log.warn( "No port given, reverting to port " +
793 "from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700794 port = self.port
795 query = "/" + mac + "/" + vlan
796 response = self.send( ip, port, url="/hosts" + query )
797 if response:
798 # NOTE: What if the person wants other values? would it be better
799 # to have a function that gets a key and return a value instead?
800 # This function requires mac and vlan and returns an ID which
801 # makes this current function useless
802 if 200 <= response[ 0 ] <= 299:
803 output = response[ 1 ]
804 hostId = json.loads( output ).get( 'id' )
805 return hostId
806 else:
807 main.log.error( "Error with REST request, response was: " +
808 str( response ) )
809 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700810 except ( AttributeError, TypeError ):
811 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700812 return None
Jon Halle401b092015-09-23 13:34:24 -0700813 except Exception:
814 main.log.exception( self.name + ": Uncaught exception!" )
815 main.cleanup()
816 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700817
818 def topology( self, ip="DEFAULT", port="DEFAULT" ):
819 """
820 Description:
821 Gets the overview of network topology
822 Returns:
823 Returns a dictionary containing information about network topology;
824 Returns None for exception
825 """
826 try:
827 output = None
828 if ip == "DEFAULT":
829 main.log.warn( "No ip given, reverting to ip from topo file" )
830 ip = self.ip_address
831 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -0700832 main.log.warn( "No port given, reverting to port " +
833 "from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700834 port = self.port
835 response = self.send( ip, port, url="/topology" )
836 if response:
837 if 200 <= response[ 0 ] <= 299:
838 output = response[ 1 ]
839 a = json.loads( output )
840 b = json.dumps( a )
841 return b
842 else:
843 main.log.error( "Error with REST request, response was: " +
844 str( response ) )
845 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -0700846 except ( AttributeError, TypeError ):
847 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700848 return None
Jon Halle401b092015-09-23 13:34:24 -0700849 except Exception:
850 main.log.exception( self.name + ": Uncaught exception!" )
851 main.cleanup()
852 main.exit()
853
854 def devices( self, ip="DEFAULT", port="DEFAULT" ):
855 """
856 Description:
857 Get the devices discovered by ONOS is json string format
858 Returns:
859 a json string of the devices currently discovered by ONOS OR
860 main.FALSE if there is an error in the request OR
861 Returns None for exception
862 """
863 try:
864 output = None
865 if ip == "DEFAULT":
866 main.log.warn( "No ip given, reverting to ip from topo file" )
867 ip = self.ip_address
868 if port == "DEFAULT":
869 main.log.warn( "No port given, reverting to port " +
870 "from topo file" )
871 port = self.port
872 response = self.send( ip, port, url="/devices" )
873 if response:
874 if 200 <= response[ 0 ] <= 299:
875 output = response[ 1 ]
876 a = json.loads( output ).get( 'devices' )
877 assert a is not None, "Error parsing json object"
878 b = json.dumps( a )
879 return b
880 else:
881 main.log.error( "Error with REST request, response was: " +
882 str( response ) )
883 return main.FALSE
884 except ( AttributeError, AssertionError, TypeError ):
885 main.log.exception( self.name + ": Object not as expected" )
886 return None
887 except Exception:
888 main.log.exception( self.name + ": Uncaught exception!" )
889 main.cleanup()
890 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700891
892 def getIntentState( self, intentsId, intentsJson=None,
893 ip="DEFAULT", port="DEFAULT" ):
894 """
895 Description:
896 Get intent state.
897 Accepts a single intent ID (string type) or a list of intent IDs.
898 Returns the state(string type) of the id if a single intent ID is
899 accepted.
900 Required:
901 intentId: intent ID (string type)
902 intentsJson: parsed json object from the onos:intents api
903 Returns:
904 Returns a dictionary with intent IDs as the key and its
905 corresponding states as the values; Returns None for invalid IDs or
906 Type error and any exceptions
907 NOTE:
908 An intent's state consist of INSTALLED,WITHDRAWN etc.
909 """
910 try:
911 state = "State is Undefined"
912 if not intentsJson:
913 intentsJsonTemp = json.loads( self.intents() )
914 else:
915 intentsJsonTemp = json.loads( intentsJson )
916 if isinstance( intentsId, types.StringType ):
917 for intent in intentsJsonTemp:
918 if intentsId == intent[ 'id' ]:
919 state = intent[ 'state' ]
920 return state
921 main.log.info( "Cannot find intent ID" + str( intentsId ) +
922 " on the list" )
923 return state
924 elif isinstance( intentsId, types.ListType ):
925 dictList = []
926 for i in xrange( len( intentsId ) ):
927 stateDict = {}
928 for intents in intentsJsonTemp:
929 if intentsId[ i ] == intents[ 'id' ]:
930 stateDict[ 'state' ] = intents[ 'state' ]
931 stateDict[ 'id' ] = intentsId[ i ]
932 dictList.append( stateDict )
933 break
934 if len( intentsId ) != len( dictList ):
935 main.log.info( "Cannot find some of the intent ID state" )
936 return dictList
937 else:
938 main.log.info( "Invalid intents ID entry" )
939 return None
940
Jon Halle401b092015-09-23 13:34:24 -0700941 except ( AttributeError, TypeError ):
942 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700943 return None
Jon Halle401b092015-09-23 13:34:24 -0700944 except Exception:
945 main.log.exception( self.name + ": Uncaught exception!" )
946 main.cleanup()
947 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700948
949 def checkIntentState( self, intentsId="ALL", expectedState='INSTALLED',
950 ip="DEFAULT", port="DEFAULT"):
951 """
952 Description:
953 Check intents state based on expected state which defaults to
954 INSTALLED state
955 Required:
956 intentsId - List of intents ID to be checked
957 Optional:
958 expectedState - Check the expected state(s) of each intents
959 state in the list.
960 *NOTE: You can pass in a list of expected state,
961 Eg: expectedState = [ 'INSTALLED' , 'INSTALLING' ]
962 Return:
963 Returns main.TRUE only if all intent are the same as expected states
964 , otherwise, returns main.FALSE; Returns None for general exception
965 """
966 try:
967 # Generating a dictionary: intent id as a key and state as value
968 returnValue = main.TRUE
969 if intentsId == "ALL":
970 intentsId = self.getIntentsId( ip=ip, port=port )
971 intentsDict = self.getIntentState( intentsId, ip=ip, port=port )
972
973 #print "len of intentsDict ", str( len( intentsDict ) )
974 if len( intentsId ) != len( intentsDict ):
975 main.log.error( self.name + ": There is something wrong " +
976 "getting intents state" )
977 return main.FALSE
978
979 if isinstance( expectedState, types.StringType ):
980 for intents in intentsDict:
981 if intents.get( 'state' ) != expectedState:
982 main.log.debug( self.name + " : Intent ID - " +
983 intents.get( 'id' ) +
984 " actual state = " +
985 intents.get( 'state' )
986 + " does not equal expected state = "
987 + expectedState )
988 returnValue = main.FALSE
989
990 elif isinstance( expectedState, types.ListType ):
991 for intents in intentsDict:
992 if not any( state == intents.get( 'state' ) for state in
993 expectedState ):
994 main.log.debug( self.name + " : Intent ID - " +
995 intents.get( 'id' ) +
996 " actual state = " +
997 intents.get( 'state' ) +
998 " does not equal expected states = "
999 + str( expectedState ) )
1000 returnValue = main.FALSE
1001
1002 if returnValue == main.TRUE:
1003 main.log.info( self.name + ": All " +
1004 str( len( intentsDict ) ) +
1005 " intents are in " + str( expectedState ) +
1006 " state" )
1007 return returnValue
Jon Halle401b092015-09-23 13:34:24 -07001008 except ( AttributeError, TypeError ):
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001009 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001010 return None
Jon Halle401b092015-09-23 13:34:24 -07001011 except Exception:
1012 main.log.exception( self.name + ": Uncaught exception!" )
1013 main.cleanup()
1014 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001015
1016 def flows( self, ip="DEFAULT", port="DEFAULT" ):
1017 """
1018 Description:
1019 Get flows currently added to the system
1020 NOTE:
1021 The flows -j cli command has completely different format than
Jon Halle401b092015-09-23 13:34:24 -07001022 the REST output
1023
1024 Returns None for exception
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001025 """
1026 try:
1027 output = None
1028 if ip == "DEFAULT":
1029 main.log.warn( "No ip given, reverting to ip from topo file" )
1030 ip = self.ip_address
1031 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -07001032 main.log.warn( "No port given, reverting to port " +
1033 "from topo file" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001034 port = self.port
1035 response = self.send( ip, port, url="/flows" )
1036 if response:
1037 if 200 <= response[ 0 ] <= 299:
1038 output = response[ 1 ]
1039 a = json.loads( output ).get( 'flows' )
Jon Halle401b092015-09-23 13:34:24 -07001040 assert a is not None, "Error parsing json object"
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001041 b = json.dumps( a )
1042 return b
1043 else:
1044 main.log.error( "Error with REST request, response was: " +
1045 str( response ) )
1046 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -07001047 except ( AttributeError, AssertionError, TypeError ):
1048 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001049 return None
Jon Halle401b092015-09-23 13:34:24 -07001050 except Exception:
1051 main.log.exception( self.name + ": Uncaught exception!" )
1052 main.cleanup()
1053 main.exit()
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001054
Jon Halle401b092015-09-23 13:34:24 -07001055 def getFlows( self, deviceId, flowId=None, ip="DEFAULT", port="DEFAULT" ):
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001056 """
1057 Description:
1058 Gets all the flows of the device or get a specific flow in the
1059 device by giving its flow ID
1060 Required:
Jon Halle401b092015-09-23 13:34:24 -07001061 str deviceId - device/switch Id
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001062 Optional:
1063 int/hex flowId - ID of the flow
1064 """
1065 try:
1066 output = None
1067 if ip == "DEFAULT":
1068 main.log.warn( "No ip given, reverting to ip from topo file" )
1069 ip = self.ip_address
1070 if port == "DEFAULT":
Jon Hallf7234882015-08-28 13:16:31 -07001071 main.log.warn( "No port given, reverting to port " +
1072 "from topo file" )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001073 port = self.port
Jon Halle401b092015-09-23 13:34:24 -07001074 url = "/flows/" + deviceId
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001075 if flowId:
1076 url += "/" + str( int( flowId ) )
1077 print url
1078 response = self.send( ip, port, url=url )
1079 if response:
1080 if 200 <= response[ 0 ] <= 299:
1081 output = response[ 1 ]
1082 a = json.loads( output ).get( 'flows' )
Jon Halle401b092015-09-23 13:34:24 -07001083 assert a is not None, "Error parsing json object"
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001084 b = json.dumps( a )
1085 return b
1086 else:
1087 main.log.error( "Error with REST request, response was: " +
1088 str( response ) )
1089 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -07001090 except ( AttributeError, AssertionError, TypeError ):
1091 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001092 return None
Jon Halle401b092015-09-23 13:34:24 -07001093 except Exception:
1094 main.log.exception( self.name + ": Uncaught exception!" )
1095 main.cleanup()
1096 main.exit()
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001097
GlennRC073e8bc2015-10-27 17:11:28 -07001098 def sendFlow( self, deviceId, flowJson, ip="DEFAULT", port="DEFAULT", debug=False ):
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001099 """
1100 Description:
GlennRC073e8bc2015-10-27 17:11:28 -07001101 Sends a single flow to the specified device. This function exists
1102 so you can bypass the addFLow driver and send your own custom flow.
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001103 Required:
GlennRC073e8bc2015-10-27 17:11:28 -07001104 * The flow in json
1105 * the device id to add the flow to
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001106 Returns:
1107 Returns main.TRUE for successful requests; Returns main.FALSE
1108 if error on requests;
1109 Returns None for exceptions
1110 NOTE:
1111 The ip and port option are for the requests input's ip and port
1112 of the ONOS node
1113 """
GlennRC073e8bc2015-10-27 17:11:28 -07001114
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001115 try:
GlennRC073e8bc2015-10-27 17:11:28 -07001116 if debug: main.log.debug( "Adding flow: " + self.pprint( flowJson ) )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001117 output = None
1118 if ip == "DEFAULT":
1119 main.log.warn( "No ip given, reverting to ip from topo file" )
1120 ip = self.ip_address
1121 if port == "DEFAULT":
1122 main.log.warn( "No port given, reverting to port " +
1123 "from topo file" )
1124 port = self.port
1125 url = "/flows/" + deviceId
1126 response = self.send( ip,
1127 port,
1128 method="POST",
1129 url=url,
1130 data=json.dumps( flowJson ) )
1131 if response:
1132 if 201:
1133 main.log.info( self.name + ": Successfully POST flow" +
1134 "in device: " + str( deviceId ) )
1135 return main.TRUE
1136 else:
1137 main.log.error( "Error with REST request, response was: " +
1138 str( response ) )
1139 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -07001140 except NotImplementedError as e:
1141 raise e # Inform the caller
1142 except ( AttributeError, TypeError ):
1143 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001144 return None
Jon Halle401b092015-09-23 13:34:24 -07001145 except Exception:
1146 main.log.exception( self.name + ": Uncaught exception!" )
1147 main.cleanup()
1148 main.exit()
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001149
GlennRC073e8bc2015-10-27 17:11:28 -07001150 def addFlow( self,
1151 deviceId,
1152 appId=0,
1153 ingressPort="",
1154 egressPort="",
1155 ethType="",
1156 ethSrc="",
1157 ethDst="",
1158 vlan="",
1159 ipProto="",
1160 ipSrc=(),
1161 ipDst=(),
1162 tcpSrc="",
1163 tcpDst="",
GlennRC956ea742015-11-05 16:14:15 -08001164 udpDst="",
1165 udpSrc="",
1166 mpls="",
GlennRC073e8bc2015-10-27 17:11:28 -07001167 ip="DEFAULT",
1168 port="DEFAULT",
1169 debug=False ):
1170 """
1171 Description:
1172 Creates a single flow in the specified device
1173 Required:
1174 * deviceId: id of the device
1175 Optional:
1176 * ingressPort: port ingress device
1177 * egressPort: port of egress device
1178 * ethType: specify ethType
1179 * ethSrc: specify ethSrc ( i.e. src mac addr )
1180 * ethDst: specify ethDst ( i.e. dst mac addr )
1181 * ipProto: specify ip protocol
1182 * ipSrc: specify ip source address with mask eg. ip#/24
1183 as a tuple (type, ip#)
1184 * ipDst: specify ip destination address eg. ip#/24
1185 as a tuple (type, ip#)
1186 * tcpSrc: specify tcp source port
1187 * tcpDst: specify tcp destination port
1188 Returns:
1189 Returns main.TRUE for successful requests; Returns main.FALSE
1190 if error on requests;
1191 Returns None for exceptions
1192 NOTE:
1193 The ip and port option are for the requests input's ip and port
1194 of the ONOS node
1195 """
suibin zhangd0f09b32016-03-29 00:57:57 -07001196
GlennRC073e8bc2015-10-27 17:11:28 -07001197 try:
1198 flowJson = { "priority":100,
1199 "isPermanent":"true",
1200 "timeout":0,
1201 "deviceId":deviceId,
1202 "treatment":{"instructions":[]},
1203 "selector": {"criteria":[]}}
1204 if appId:
1205 flowJson[ "appId" ] = appId
1206 if egressPort:
1207 flowJson[ 'treatment' ][ 'instructions' ].append( {
1208 "type":"OUTPUT",
1209 "port":egressPort } )
1210 if ingressPort:
1211 flowJson[ 'selector' ][ 'criteria' ].append( {
1212 "type":"IN_PORT",
1213 "port":ingressPort } )
1214 if ethType:
1215 flowJson[ 'selector' ][ 'criteria' ].append( {
1216 "type":"ETH_TYPE",
1217 "ethType":ethType } )
1218 if ethSrc:
1219 flowJson[ 'selector' ][ 'criteria' ].append( {
1220 "type":"ETH_SRC",
1221 "mac":ethSrc } )
1222 if ethDst:
1223 flowJson[ 'selector' ][ 'criteria' ].append( {
1224 "type":"ETH_DST",
1225 "mac":ethDst } )
1226 if vlan:
1227 flowJson[ 'selector' ][ 'criteria' ].append( {
1228 "type":"VLAN_VID",
1229 "vlanId":vlan } )
GlennRC956ea742015-11-05 16:14:15 -08001230 if mpls:
1231 flowJson[ 'selector' ][ 'criteria' ].append( {
1232 "type":"MPLS_LABEL",
1233 "label":mpls } )
GlennRC073e8bc2015-10-27 17:11:28 -07001234 if ipSrc:
1235 flowJson[ 'selector' ][ 'criteria' ].append( {
1236 "type":ipSrc[0],
1237 "ip":ipSrc[1] } )
1238 if ipDst:
1239 flowJson[ 'selector' ][ 'criteria' ].append( {
1240 "type":ipDst[0],
1241 "ip":ipDst[1] } )
1242 if tcpSrc:
1243 flowJson[ 'selector' ][ 'criteria' ].append( {
1244 "type":"TCP_SRC",
1245 "tcpPort": tcpSrc } )
1246 if tcpDst:
1247 flowJson[ 'selector' ][ 'criteria' ].append( {
1248 "type":"TCP_DST",
1249 "tcpPort": tcpDst } )
GlennRC956ea742015-11-05 16:14:15 -08001250 if udpSrc:
1251 flowJson[ 'selector' ][ 'criteria' ].append( {
1252 "type":"UDP_SRC",
1253 "udpPort": udpSrc } )
1254 if udpDst:
1255 flowJson[ 'selector' ][ 'criteria' ].append( {
1256 "type":"UDP_DST",
1257 "udpPort": udpDst } )
GlennRC073e8bc2015-10-27 17:11:28 -07001258 if ipProto:
1259 flowJson[ 'selector' ][ 'criteria' ].append( {
1260 "type":"IP_PROTO",
1261 "protocol": ipProto } )
1262
1263 return self.sendFlow( deviceId=deviceId, flowJson=flowJson, debug=debug )
1264
1265 except ( AttributeError, TypeError ):
1266 main.log.exception( self.name + ": Object not as expected" )
1267 return None
1268 except Exception:
1269 main.log.exception( self.name + ": Uncaught exception!" )
1270 main.cleanup()
1271 main.exit()
1272
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001273 def removeFlow( self, deviceId, flowId,
1274 ip="DEFAULT", port="DEFAULT" ):
1275 """
1276 Description:
1277 Remove specific device flow
1278 Required:
1279 str deviceId - id of the device
1280 str flowId - id of the flow
1281 Return:
1282 Returns main.TRUE if successfully deletes flows, otherwise
1283 Returns main.FALSE, Returns None on error
1284 """
1285 try:
1286 output = None
1287 if ip == "DEFAULT":
1288 main.log.warn( "No ip given, reverting to ip from topo file" )
1289 ip = self.ip_address
1290 if port == "DEFAULT":
1291 main.log.warn( "No port given, reverting to port " +
1292 "from topo file" )
1293 port = self.port
1294 # NOTE: REST url requires the intent id to be in decimal form
1295 query = "/" + str( deviceId ) + "/" + str( int( flowId ) )
1296 response = self.send( ip,
1297 port,
1298 method="DELETE",
1299 url="/flows" + query )
1300 if response:
1301 if 200 <= response[ 0 ] <= 299:
1302 return main.TRUE
1303 else:
1304 main.log.error( "Error with REST request, response was: " +
1305 str( response ) )
1306 return main.FALSE
Jon Halle401b092015-09-23 13:34:24 -07001307 except ( AttributeError, TypeError ):
1308 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001309 return None
Jon Halle401b092015-09-23 13:34:24 -07001310 except Exception:
1311 main.log.exception( self.name + ": Uncaught exception!" )
1312 main.cleanup()
1313 main.exit()
kelvin-onlab9b42b0a2015-08-05 14:43:58 -07001314
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001315 def checkFlowsState( self , ip="DEFAULT", port="DEFAULT" ):
1316 """
1317 Description:
1318 Check if all the current flows are in ADDED state
1319 Return:
1320 returnValue - Returns main.TRUE only if all flows are in
1321 return main.FALSE otherwise;
1322 Returns None for exception
1323 """
1324 try:
1325 tempFlows = json.loads( self.flows( ip=ip, port=port ) )
1326 returnValue = main.TRUE
suibin zhangd0f09b32016-03-29 00:57:57 -07001327 numPending = 0
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001328 for flow in tempFlows:
1329 if flow.get( 'state' ) != 'ADDED':
suibin zhangd0f09b32016-03-29 00:57:57 -07001330 '''
1331 main.log.debug( self.name + ": flow Id: " +
1332 str( flow.get( 'id' ) ) +
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001333 " | state:" +
1334 str( flow.get( 'state' ) ) )
suibin zhangd0f09b32016-03-29 00:57:57 -07001335 '''
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001336 returnValue = main.FALSE
suibin zhangd0f09b32016-03-29 00:57:57 -07001337 numPending += 1
1338 main.log.info("Number of non-ADDED flows are: " + str(numPending))
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001339 return returnValue
Jon Halle401b092015-09-23 13:34:24 -07001340 except ( AttributeError, TypeError ):
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001341 main.log.exception( self.name + ": Object not as expected" )
kelvin-onlab03eb88d2015-07-22 10:29:02 -07001342 return None
1343 except Exception:
1344 main.log.exception( self.name + ": Uncaught exception!" )
1345 main.cleanup()
1346 main.exit()
Jon Hall66e001c2015-11-12 09:45:10 -08001347
suibin zhangd0f09b32016-03-29 00:57:57 -07001348 def addFlow( self,
1349 deviceId,
1350 appId=0,
1351 ingressPort="",
1352 egressPort="",
1353 ethType="",
1354 ethSrc="",
1355 ethDst="",
1356 vlan="",
1357 ipProto="",
1358 ipSrc=(),
1359 ipDst=(),
1360 tcpSrc="",
1361 tcpDst="",
1362 udpDst="",
1363 udpSrc="",
1364 mpls="",
1365 ip="DEFAULT",
1366 port="DEFAULT",
1367 debug=False ):
1368
1369 """
1370 Description:
1371 Creates a single flow in the specified device
1372 Required:
1373 * deviceId: id of the device
1374 Optional:
1375 * ingressPort: port ingress device
1376 * egressPort: port of egress device
1377 * ethType: specify ethType
1378 * ethSrc: specify ethSrc ( i.e. src mac addr )
1379 * ethDst: specify ethDst ( i.e. dst mac addr )
1380 * ipProto: specify ip protocol
1381 * ipSrc: specify ip source address with mask eg. ip#/24
1382 as a tuple (type, ip#)
1383 * ipDst: specify ip destination address eg. ip#/24
1384 as a tuple (type, ip#)
1385 * tcpSrc: specify tcp source port
1386 * tcpDst: specify tcp destination port
1387 Returns:
1388 Returns main.TRUE for successful requests; Returns main.FALSE
1389 if error on requests;
1390 Returns None for exceptions
1391 NOTE:
1392 The ip and port option are for the requests input's ip and port
1393 of the ONOS node
1394 """
1395 try:
1396 flowJson = { "priority":100,
1397 "isPermanent":"true",
1398 "timeout":0,
1399 "deviceId":deviceId,
1400 "treatment":{"instructions":[]},
1401 "selector": {"criteria":[]}}
1402 if appId:
1403 flowJson[ "appId" ] = appId
1404 if egressPort:
1405 flowJson[ 'treatment' ][ 'instructions' ].append( {
1406 "type":"OUTPUT",
1407 "port":egressPort } )
1408 if ingressPort:
1409 flowJson[ 'selector' ][ 'criteria' ].append( {
1410 "type":"IN_PORT",
1411 "port":ingressPort } )
1412 if ethType:
1413 flowJson[ 'selector' ][ 'criteria' ].append( {
1414 "type":"ETH_TYPE",
1415 "ethType":ethType } )
1416 if ethSrc:
1417 flowJson[ 'selector' ][ 'criteria' ].append( {
1418 "type":"ETH_SRC",
1419 "mac":ethSrc } )
1420 if ethDst:
1421 flowJson[ 'selector' ][ 'criteria' ].append( {
1422 "type":"ETH_DST",
1423 "mac":ethDst } )
1424 if vlan:
1425 flowJson[ 'selector' ][ 'criteria' ].append( {
1426 "type":"VLAN_VID",
1427 "vlanId":vlan } )
1428 if mpls:
1429 flowJson[ 'selector' ][ 'criteria' ].append( {
1430 "type":"MPLS_LABEL",
1431 "label":mpls } )
1432 if ipSrc:
1433 flowJson[ 'selector' ][ 'criteria' ].append( {
1434 "type":ipSrc[0],
1435 "ip":ipSrc[1] } )
1436 if ipDst:
1437 flowJson[ 'selector' ][ 'criteria' ].append( {
1438 "type":ipDst[0],
1439 "ip":ipDst[1] } )
1440 if tcpSrc:
1441 flowJson[ 'selector' ][ 'criteria' ].append( {
1442 "type":"TCP_SRC",
1443 "tcpPort": tcpSrc } )
1444 if tcpDst:
1445 flowJson[ 'selector' ][ 'criteria' ].append( {
1446 "type":"TCP_DST",
1447 "tcpPort": tcpDst } )
1448 if udpSrc:
1449 flowJson[ 'selector' ][ 'criteria' ].append( {
1450 "type":"UDP_SRC",
1451 "udpPort": udpSrc } )
1452 if udpDst:
1453 flowJson[ 'selector' ][ 'criteria' ].append( {
1454 "type":"UDP_DST",
1455 "udpPort": udpDst } )
1456 if ipProto:
1457 flowJson[ 'selector' ][ 'criteria' ].append( {
1458 "type":"IP_PROTO",
1459 "protocol": ipProto } )
1460
1461 return self.sendFlow( deviceId=deviceId, flowJson=flowJson, debug=debug )
1462
1463 except ( AttributeError, TypeError ):
1464 main.log.exception( self.name + ": Object not as expected" )
1465 return None
1466 except Exception:
1467 main.log.exception( self.name + ": Uncaught exception!" )
1468 main.cleanup()
1469 main.exit()
1470
1471 def removeFlow( self, deviceId, flowId,
1472 ip="DEFAULT", port="DEFAULT" ):
1473 """
1474 Description:
1475 Remove specific device flow
1476 Required:
1477 str deviceId - id of the device
1478 str flowId - id of the flow
1479 Return:
1480 Returns main.TRUE if successfully deletes flows, otherwise
1481 Returns main.FALSE, Returns None on error
1482 """
1483 try:
1484 output = None
1485 if ip == "DEFAULT":
1486 main.log.warn( "No ip given, reverting to ip from topo file" )
1487 ip = self.ip_address
1488 if port == "DEFAULT":
1489 main.log.warn( "No port given, reverting to port " +
1490 "from topo file" )
1491 port = self.port
1492 # NOTE: REST url requires the intent id to be in decimal form
1493 query = "/" + str( deviceId ) + "/" + str( int( flowId ) )
1494 response = self.send( ip,
1495 port,
1496 method="DELETE",
1497 url="/flows" + query )
1498 if response:
1499 if 200 <= response[ 0 ] <= 299:
1500 return main.TRUE
1501 else:
1502 main.log.error( "Error with REST request, response was: " +
1503 str( response ) )
1504 return main.FALSE
1505 except ( AttributeError, TypeError ):
1506 main.log.exception( self.name + ": Object not as expected" )
1507 return None
1508 except Exception:
1509 main.log.exception( self.name + ": Uncaught exception!" )
1510 main.cleanup()
1511 main.exit()
1512
1513 def createFlowBatch( self,
1514 numSw = 1,
suibin zhanga82fe3f2016-03-29 11:26:21 -07001515 swIndex = 1,
1516 batchSize = 1,
suibin zhangd0f09b32016-03-29 00:57:57 -07001517 batchIndex = 1,
1518 deviceIdpreFix = "of:",
1519 appId=0,
1520 deviceID="",
1521 ingressPort="",
1522 egressPort="",
1523 ethType="",
1524 ethSrc="",
1525 ethDst="",
1526 vlan="",
1527 ipProto="",
1528 ipSrc=(),
1529 ipDst=(),
1530 tcpSrc="",
1531 tcpDst="",
1532 udpDst="",
1533 udpSrc="",
1534 mpls="",
1535 ip="DEFAULT",
1536 port="DEFAULT",
1537 debug=False ):
1538 """
1539 Description:
1540 Creates a single flow in the specified device
1541 Required:
1542 * deviceId: id of the device
1543 Optional:
1544 * ingressPort: port ingress device
1545 * egressPort: port of egress device
1546 * ethType: specify ethType
1547 * ethSrc: specify ethSrc ( i.e. src mac addr )
1548 * ethDst: specify ethDst ( i.e. dst mac addr )
1549 * ipProto: specify ip protocol
1550 * ipSrc: specify ip source address with mask eg. ip#/24
1551 as a tuple (type, ip#)
1552 * ipDst: specify ip destination address eg. ip#/24
1553 as a tuple (type, ip#)
1554 * tcpSrc: specify tcp source port
1555 * tcpDst: specify tcp destination port
1556 Returns:
1557 Returns main.TRUE for successful requests; Returns main.FALSE
1558 if error on requests;
1559 Returns None for exceptions
1560 NOTE:
1561 The ip and port option are for the requests input's ip and port
1562 of the ONOS node
1563 """
1564 from pprint import pprint
1565
1566 flowJsonList = []
1567 flowJsonBatch = {"flows":flowJsonList}
suibin zhanga82fe3f2016-03-29 11:26:21 -07001568 dev = swIndex
suibin zhangd0f09b32016-03-29 00:57:57 -07001569
suibin zhanga82fe3f2016-03-29 11:26:21 -07001570 for fl in range(1, batchSize + 1):
1571 flowJson = { "priority":100,
suibin zhangd0f09b32016-03-29 00:57:57 -07001572 "deviceId":"",
1573 "isPermanent":"true",
1574 "timeout":0,
1575 "treatment":{"instructions":[]},
1576 "selector": {"criteria":[]}}
1577
suibin zhang5c735ca2016-03-30 16:01:06 -07001578 #main.log.info("fl: " + str(fl))
suibin zhanga82fe3f2016-03-29 11:26:21 -07001579 if dev <= numSw:
1580 deviceId = deviceIdpreFix + "{0:0{1}x}".format(dev,16)
1581 #print deviceId
1582 flowJson['deviceId'] = deviceId
1583 dev += 1
1584 else:
1585 dev = 1
suibin zhangd0f09b32016-03-29 00:57:57 -07001586 deviceId = deviceIdpreFix + "{0:0{1}x}".format(dev,16)
1587 #print deviceId
1588 flowJson['deviceId'] = deviceId
suibin zhangff4abfe2016-03-29 11:52:08 -07001589 dev += 1
suibin zhangd0f09b32016-03-29 00:57:57 -07001590
1591 # ethSrc starts with "0"; ethDst starts with "1"
1592 # 3 Hex digit of device number; 4 digits of batch index number; 4 digits of batch size
suibin zhanga82fe3f2016-03-29 11:26:21 -07001593 ethS = "{0:0{1}x}".format(dev,4) + "{0:0{1}x}".format(batchIndex,4) + "{0:0{1}x}".format(fl,4)
1594 ethSrc = ':'.join(ethS[i:i+2] for i in range(0,len(ethS),2))
1595 ethD = "1" + "{0:0{1}x}".format(dev,3) + "{0:0{1}x}".format(batchIndex,4) + "{0:0{1}x}".format(fl,4)
1596 ethDst = ':'.join(ethD[i:i+2] for i in range(0,len(ethD),2))
suibin zhangd0f09b32016-03-29 00:57:57 -07001597
suibin zhanga82fe3f2016-03-29 11:26:21 -07001598 if appId:
1599 flowJson[ "appId" ] = appId
suibin zhangd0f09b32016-03-29 00:57:57 -07001600
suibin zhanga82fe3f2016-03-29 11:26:21 -07001601 if egressPort:
1602 flowJson[ 'treatment' ][ 'instructions' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001603 "type":"OUTPUT",
1604 "port":egressPort } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001605 if ingressPort:
1606 flowJson[ 'selector' ][ 'criteria' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001607 "type":"IN_PORT",
1608 "port":ingressPort } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001609 if ethType:
1610 flowJson[ 'selector' ][ 'criteria' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001611 "type":"ETH_TYPE",
1612 "ethType":ethType } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001613 if ethSrc:
1614 flowJson[ 'selector' ][ 'criteria' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001615 "type":"ETH_SRC",
1616 "mac":ethSrc } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001617 if ethDst:
1618 flowJson[ 'selector' ][ 'criteria' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001619 "type":"ETH_DST",
1620 "mac":ethDst } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001621 if vlan:
1622 flowJson[ 'selector' ][ 'criteria' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001623 "type":"VLAN_VID",
1624 "vlanId":vlan } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001625 if mpls:
1626 flowJson[ 'selector' ][ 'criteria' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001627 "type":"MPLS_LABEL",
1628 "label":mpls } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001629 if ipSrc:
1630 flowJson[ 'selector' ][ 'criteria' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001631 "type":ipSrc[0],
1632 "ip":ipSrc[1] } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001633 if ipDst:
1634 flowJson[ 'selector' ][ 'criteria' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001635 "type":ipDst[0],
1636 "ip":ipDst[1] } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001637 if tcpSrc:
1638 flowJson[ 'selector' ][ 'criteria' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001639 "type":"TCP_SRC",
1640 "tcpPort": tcpSrc } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001641 if tcpDst:
1642 flowJson[ 'selector' ][ 'criteria' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001643 "type":"TCP_DST",
1644 "tcpPort": tcpDst } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001645 if udpSrc:
1646 flowJson[ 'selector' ][ 'criteria' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001647 "type":"UDP_SRC",
1648 "udpPort": udpSrc } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001649 if udpDst:
1650 flowJson[ 'selector' ][ 'criteria' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001651 "type":"UDP_DST",
1652 "udpPort": udpDst } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001653 if ipProto:
1654 flowJson[ 'selector' ][ 'criteria' ].append( {
suibin zhangd0f09b32016-03-29 00:57:57 -07001655 "type":"IP_PROTO",
1656 "protocol": ipProto } )
suibin zhanga82fe3f2016-03-29 11:26:21 -07001657 #pprint(flowJson)
1658 flowJsonList.append(flowJson)
suibin zhangd0f09b32016-03-29 00:57:57 -07001659
suibin zhanga82fe3f2016-03-29 11:26:21 -07001660 main.log.info("Number of flows in batch: " + str( len(flowJsonList) ) )
suibin zhangd0f09b32016-03-29 00:57:57 -07001661 flowJsonBatch['flows'] = flowJsonList
suibin zhang570cb452016-03-29 19:03:15 -07001662 #pprint(flowJsonBatch)
suibin zhangd0f09b32016-03-29 00:57:57 -07001663
1664 return flowJsonBatch
1665
1666 def sendFlowBatch( self, batch={}, ip="DEFAULT", port="DEFAULT", debug=False ):
1667 """
1668 Description:
1669 Sends a single flow to the specified device. This function exists
1670 so you can bypass the addFLow driver and send your own custom flow.
1671 Required:
1672 * The flow in json
1673 * the device id to add the flow to
1674 Returns:
1675 Returns main.TRUE for successful requests; Returns main.FALSE
1676 if error on requests;
1677 Returns None for exceptions
1678 NOTE:
1679 The ip and port option are for the requests input's ip and port
1680 of the ONOS node
1681 """
1682 import time
1683
1684 try:
1685 if debug: main.log.debug( "Adding flow: " + self.pprint( batch ) )
1686 output = None
1687 if ip == "DEFAULT":
1688 main.log.warn( "No ip given, reverting to ip from topo file" )
1689 ip = self.ip_address
1690 if port == "DEFAULT":
1691 main.log.warn( "No port given, reverting to port " +
1692 "from topo file" )
1693 port = self.port
1694 url = "/flows/"
1695 response = self.send( ip,
1696 port,
1697 method="POST",
1698 url=url,
1699 data=json.dumps( batch ) )
1700 #main.log.info("Post response is: ", str(response[0]))
1701 if response[0] == 200:
1702 main.log.info( self.name + ": Successfully POST flow" )
suibin zhang570cb452016-03-29 19:03:15 -07001703 return main.TRUE, response
suibin zhangd0f09b32016-03-29 00:57:57 -07001704 else:
1705 main.log.error( "Error with REST request, response was: " +
1706 str( response ) )
1707 return main.FALSE
1708 except NotImplementedError as e:
1709 raise e # Inform the caller
1710 except ( AttributeError, TypeError ):
1711 main.log.exception( self.name + ": Object not as expected" )
1712 return None
1713 except Exception:
1714 main.log.exception( self.name + ": Uncaught exception!" )
1715 main.cleanup()
1716 main.exit()
1717
1718 def removeFlowBatch( self, batch={},
1719 ip="DEFAULT", port="DEFAULT" ):
1720 """
1721 Description:
1722 Remove a batch of flows
1723 Required:
1724 flow batch
1725 Return:
1726 Returns main.TRUE if successfully deletes flows, otherwise
1727 Returns main.FALSE, Returns None on error
1728 """
1729 try:
1730 output = None
1731 if ip == "DEFAULT":
1732 main.log.warn( "No ip given, reverting to ip from topo file" )
1733 ip = self.ip_address
1734 if port == "DEFAULT":
1735 main.log.warn( "No port given, reverting to port " +
1736 "from topo file" )
1737 port = self.port
1738 # NOTE: REST url requires the intent id to be in decimal form
1739
1740 response = self.send( ip,
1741 port,
1742 method="DELETE",
suibin zhang570cb452016-03-29 19:03:15 -07001743 url="/flows/",
1744 data = json.dumps(batch) )
suibin zhangd0f09b32016-03-29 00:57:57 -07001745 if response:
1746 if 200 <= response[ 0 ] <= 299:
1747 return main.TRUE
1748 else:
1749 main.log.error( "Error with REST request, response was: " +
1750 str( response ) )
1751 return main.FALSE
1752 except ( AttributeError, TypeError ):
1753 main.log.exception( self.name + ": Object not as expected" )
1754 return None
1755 except Exception:
1756 main.log.exception( self.name + ": Uncaught exception!" )
1757 main.cleanup()
1758 main.exit()
1759
Jon Hall66e001c2015-11-12 09:45:10 -08001760 def getNetCfg( self, ip="DEFAULT", port="DEFAULT",
1761 subjectClass=None, subjectKey=None, configKey=None ):
1762 """
1763 Description:
1764 Get a json object with the ONOS network configurations
1765 Returns:
1766 A json object containing the network configuration in
1767 ONOS; Returns main.FALSE if error on requests;
1768 Returns None for exception
1769 """
1770 try:
1771 output = None
1772 if ip == "DEFAULT":
1773 main.log.warn( "No ip given, reverting to ip from topo file" )
1774 ip = self.ip_address
1775 if port == "DEFAULT":
1776 main.log.warn( "No port given, reverting to port " +
1777 "from topo file" )
1778 port = self.port
1779 url = "/network/configuration"
1780 if subjectClass:
1781 url += "/" + subjectClass
1782 if subjectKey:
1783 url += "/" + subjectKey
1784 if configKey:
1785 url += "/" + configKey
1786 response = self.send( ip, port, url=url )
1787 if response:
1788 if 200 <= response[ 0 ] <= 299:
1789 output = response[ 1 ]
1790 a = json.loads( output )
1791 b = json.dumps( a )
1792 return b
1793 elif response[ 0 ] == 404:
1794 main.log.error( "Requested configuration doesn't exist: " +
1795 str( response ) )
1796 return {}
1797 else:
1798 main.log.error( "Error with REST request, response was: " +
1799 str( response ) )
1800 return main.FALSE
1801 except ( AttributeError, TypeError ):
1802 main.log.exception( self.name + ": Object not as expected" )
1803 return None
1804 except Exception:
1805 main.log.exception( self.name + ": Uncaught exception!" )
1806 main.cleanup()
1807 main.exit()
1808
1809 def setNetCfg( self, cfgJson, ip="DEFAULT", port="DEFAULT",
1810 subjectClass=None, subjectKey=None, configKey=None ):
1811 """
1812 Description:
1813 Set a json object with the ONOS network configurations
1814 Returns:
1815 Returns main.TRUE for successful requests; Returns main.FALSE
1816 if error on requests;
1817 Returns None for exceptions
1818
1819 """
1820 try:
1821 output = None
1822 if ip == "DEFAULT":
1823 main.log.warn( "No ip given, reverting to ip from topo file" )
1824 ip = self.ip_address
1825 if port == "DEFAULT":
1826 main.log.warn( "No port given, reverting to port " +
1827 "from topo file" )
1828 port = self.port
1829 url = "/network/configuration"
1830 if subjectClass:
1831 url += "/" + subjectClass
1832 if subjectKey:
1833 url += "/" + subjectKey
1834 if configKey:
1835 url += "/" + configKey
1836 response = self.send( ip, port,
1837 method="POST",
1838 url=url,
1839 data=json.dumps( cfgJson ) )
1840 if response:
1841 if 200 <= response[ 0 ] <= 299:
1842 main.log.info( self.name + ": Successfully POST cfg" )
1843 return main.TRUE
1844 else:
1845 main.log.error( "Error with REST request, response was: " +
1846 str( response ) )
1847 return main.FALSE
1848 except ( AttributeError, TypeError ):
1849 main.log.exception( self.name + ": Object not as expected" )
1850 return None
1851 except Exception:
1852 main.log.exception( self.name + ": Uncaught exception!" )
1853 main.cleanup()
1854 main.exit()
1855
1856 def removeNetCfg( self, ip="DEFAULT", port="DEFAULT",
1857 subjectClass=None, subjectKey=None, configKey=None ):
1858 """
1859 Description:
1860 Remove a json object from the ONOS network configurations
1861 Returns:
1862 Returns main.TRUE for successful requests; Returns main.FALSE
1863 if error on requests;
1864 Returns None for exceptions
1865
1866 """
1867 try:
1868 output = None
1869 if ip == "DEFAULT":
1870 main.log.warn( "No ip given, reverting to ip from topo file" )
1871 ip = self.ip_address
1872 if port == "DEFAULT":
1873 main.log.warn( "No port given, reverting to port " +
1874 "from topo file" )
1875 port = self.port
1876 url = "/network/configuration"
1877 if subjectClass:
1878 url += "/" + subjectClass
1879 if subjectKey:
1880 url += "/" + subjectKey
1881 if configKey:
1882 url += "/" + configKey
1883 response = self.send( ip, port,
1884 method="DELETE",
1885 url=url )
1886 if response:
1887 if 200 <= response[ 0 ] <= 299:
1888 main.log.info( self.name + ": Successfully delete cfg" )
1889 return main.TRUE
1890 else:
1891 main.log.error( "Error with REST request, response was: " +
1892 str( response ) )
1893 return main.FALSE
1894 except ( AttributeError, TypeError ):
1895 main.log.exception( self.name + ": Object not as expected" )
1896 return None
1897 except Exception:
1898 main.log.exception( self.name + ": Uncaught exception!" )
1899 main.cleanup()
1900 main.exit()