blob: 0f72bf59772cd99ca5ad861a3f4fc431d8f6412d [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 Hallfc915882015-07-14 13:33:17 -070023
Jon Hallfc915882015-07-14 13:33:17 -070024from drivers.common.api.controllerdriver import Controller
25
26
27class OnosRestDriver( Controller ):
28
29 def __init__( self ):
30 super( Controller, self ).__init__()
31 self.ip_address = "localhost"
32 self.port = "8080"
33 self.user_name = "user"
34 self.password = "CHANGEME"
35
36 def connect( self, **connectargs ):
37 try:
38 for key in connectargs:
39 vars( self )[ key ] = connectargs[ key ]
40 self.name = self.options[ 'name' ]
41 except Exception as e:
42 main.log.exception( e )
43 try:
44 if os.getenv( str( self.ip_address ) ) != None:
45 self.ip_address = os.getenv( str( self.ip_address ) )
46 else:
kelvin-onlab03eb88d2015-07-22 10:29:02 -070047 main.log.info( self.name + ": ip set to " + self.ip_address )
Jon Hallfc915882015-07-14 13:33:17 -070048 except KeyError:
49 main.log.info( "Invalid host name," +
50 "defaulting to 'localhost' instead" )
51 self.ip_address = 'localhost'
52 except Exception as inst:
53 main.log.error( "Uncaught exception: " + str( inst ) )
54
55 self.handle = super( OnosRestDriver, self ).connect()
56 return self.handle
57
58 def send( self, ip, port, url, base="/onos/v1", method="GET",
59 query=None, data=None ):
60 """
61 Arguments:
62 str ip: ONOS IP Address
63 str port: ONOS REST Port
64 str url: ONOS REST url path.
65 NOTE that this is is only the relative path. IE "/devices"
66 str base: The base url for the given REST api. Applications could
67 potentially have their own base url
68 str method: HTTP method type
kelvin-onlab03eb88d2015-07-22 10:29:02 -070069 dict query: Dictionary to be sent in the query string for
Jon Hallfc915882015-07-14 13:33:17 -070070 the request
71 dict data: Dictionary to be sent in the body of the request
72 """
73 # TODO: Authentication - simple http (user,pass) tuple
74 # TODO: should we maybe just pass kwargs straight to response?
75 # TODO: Do we need to allow for other protocols besides http?
76 # ANSWER: Not yet, but potentially https with certificates
77 try:
78 path = "http://" + str( ip ) + ":" + str( port ) + base + url
79 main.log.info( "Sending request " + path + " using " +
80 method.upper() + " method." )
81 response = requests.request( method.upper(),
82 path,
83 params=query,
84 data=data )
85 return ( response.status_code, response.text.encode( 'utf8' ) )
86 except requests.exceptions:
87 main.log.exception( "Error sending request." )
88 return None
89 except Exception as e:
90 main.log.exception( e )
91 return None
kelvin-onlab03eb88d2015-07-22 10:29:02 -070092 # FIXME: add other exceptions
Jon Hallfc915882015-07-14 13:33:17 -070093
94 def intents( self, ip="DEFAULT", port="DEFAULT" ):
95 """
kelvin-onlab03eb88d2015-07-22 10:29:02 -070096 Description:
97 Gets a list of dictionary of all intents in the system
98 Returns:
99 A list of dictionary of intents in string type to match the cli
100 version for now; Returns main.FALSE if error on request;
101 Returns None for exception
Jon Hallfc915882015-07-14 13:33:17 -0700102 """
103 try:
104 output = None
105 if ip == "DEFAULT":
106 main.log.warn( "No ip given, reverting to ip from topo file" )
107 ip = self.ip_address
108 if port == "DEFAULT":
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700109 main.log.warn( "No port given, reverting to port " +
110 "from topo file" )
Jon Hallfc915882015-07-14 13:33:17 -0700111 port = self.port
112 response = self.send( ip, port, url="/intents" )
113 if response:
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700114 if 200 <= response[ 0 ] <= 299:
115 output = response[ 1 ]
116 a = json.loads( output ).get( 'intents' )
117 b = json.dumps( a )
118 return b
Jon Hallfc915882015-07-14 13:33:17 -0700119 else:
120 main.log.error( "Error with REST request, response was: " +
121 str( response ) )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700122 return main.FALSE
Jon Hallfc915882015-07-14 13:33:17 -0700123 except Exception as e:
124 main.log.exception( e )
125 return None
126
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700127 def intent( self, intentId, appId="org.onosproject.cli",
128 ip="DEFAULT", port="DEFAULT" ):
Jon Hallfc915882015-07-14 13:33:17 -0700129 """
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700130 Description:
131 Get the specific intent information of the given application ID and
132 intent ID
133 Required:
134 str intentId - Intent id in hexadecimal form
135 Optional:
136 str appId - application id of intent
137 Returns:
138 Returns an information dictionary of the given intent;
139 Returns main.FALSE if error on requests; Returns None for exception
140 NOTE:
141 The GET /intents REST api command accepts application id but the
142 api will get updated to accept application name instead
Jon Hallfc915882015-07-14 13:33:17 -0700143 """
144 try:
145 output = None
146 if ip == "DEFAULT":
147 main.log.warn( "No ip given, reverting to ip from topo file" )
148 ip = self.ip_address
149 if port == "DEFAULT":
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700150 main.log.warn( "No port given, reverting to port" +
151 "from topo file" )
Jon Hallfc915882015-07-14 13:33:17 -0700152 port = self.port
153 # NOTE: REST url requires the intent id to be in decimal form
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700154 query = "/" + str( appId ) + "/" + str( intentId )
Jon Hallfc915882015-07-14 13:33:17 -0700155 response = self.send( ip, port, url="/intents" + query )
156 if response:
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700157 if 200 <= response[ 0 ] <= 299:
158 output = response[ 1 ]
159 a = json.loads( output )
160 return a
Jon Hallfc915882015-07-14 13:33:17 -0700161 else:
162 main.log.error( "Error with REST request, response was: " +
163 str( response ) )
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700164 return main.FALSE
Jon Hallfc915882015-07-14 13:33:17 -0700165 except Exception as e:
166 main.log.exception( e )
167 return None
kelvin-onlab03eb88d2015-07-22 10:29:02 -0700168
169 def getIntentsId( self, ip="DEFAULT", port="DEFAULT" ):
170 """
171 Description:
172 Gets all intents ID using intents function
173 Returns:
174 List of intents ID;Returns None for exception; Returns None for
175 exception; Returns None for exception
176 """
177 try:
178 intentsDict = {}
179 intentsIdList = []
180 intentsDict = json.loads( self.intents( ip=ip, port=port ) )
181 for intent in intentsDict:
182 intentsIdList.append( intent.get( 'id' ) )
183
184 if not intentsIdList:
185 main.log.debug( "Cannot find any intents" )
186 return main.FALSE
187 else:
188 main.log.info( "Found intents: " + str( intentsIdList ) )
189 return main.TRUE
190
191 except Exception as e:
192 main.log.exception( e )
193 return None
194
195
196 def apps( self, ip="DEFAULT", port="DEFAULT" ):
197 """
198 Description:
199 Returns all the current application installed in the system
200 Returns:
201 List of dictionary of installed application; Returns main.FALSE for
202 error on request; Returns None for exception
203 """
204 try:
205 output = None
206 if ip == "DEFAULT":
207 main.log.warn( "No ip given, reverting to ip from topo file" )
208 ip = self.ip_address
209 if port == "DEFAULT":
210 main.log.warn( "No port given, reverting to port \
211 from topo file" )
212 port = self.port
213 response = self.send( ip, port, url="/applications" )
214 if response:
215 if 200 <= response[ 0 ] <= 299:
216 output = response[ 1 ]
217 a = json.loads( output ).get( 'applications' )
218 b = json.dumps( a )
219 return b
220 else:
221 main.log.error( "Error with REST request, response was: " +
222 str( response ) )
223 return main.FALSE
224 except Exception as e:
225 main.log.exception( e )
226 return None
227
228 def activateApp( self, appName, ip="DEFAULT", port="DEFAULT", check=True ):
229 """
230 Decription:
231 Activate an app that is already installed in ONOS
232 Optional:
233 bool check - If check is True, method will check the status
234 of the app after the command is issued
235 Returns:
236 Returns main.TRUE if the command was successfully or main.FALSE
237 if the REST responded with an error or given incorrect input;
238 Returns None for exception
239
240 """
241 try:
242 output = None
243 if ip == "DEFAULT":
244 main.log.warn( "No ip given, reverting to ip from topo file" )
245 ip = self.ip_address
246 if port == "DEFAULT":
247 main.log.warn( "No port given, reverting to port" +
248 "from topo file" )
249 port = self.port
250 query = "/" + str( appName ) + "/active"
251 response = self.send( ip, port, method="POST",
252 url="/applications" + query )
253 if response:
254 output = response[ 1 ]
255 app = json.loads( output )
256 if 200 <= response[ 0 ] <= 299:
257 if check:
258 if app.get( 'state' ) == 'ACTIVE':
259 main.log.info( self.name + ": " + appName +
260 " application" +
261 " is in ACTIVE state" )
262 return main.TRUE
263 else:
264 main.log.error( self.name + ": " + appName +
265 " application" + " is in " +
266 app.get( 'state' ) + " state" )
267 return main.FALSE
268 else:
269 main.log.warn( "Skipping " + appName +
270 "application check" )
271 return main.TRUE
272 else:
273 main.log.error( "Error with REST request, response was: " +
274 str( response ) )
275 return main.FALSE
276 except Exception as e:
277 main.log.exception( e )
278 return None
279
280 def deactivateApp( self, appName, ip="DEFAULT", port="DEFAULT",
281 check=True ):
282 """
283 Required:
284 Deactivate an app that is already activated in ONOS
285 Optional:
286 bool check - If check is True, method will check the status of the
287 app after the command is issued
288 Returns:
289 Returns main.TRUE if the command was successfully sent
290 main.FALSE if the REST responded with an error or given
291 incorrect input; Returns None for exception
292 """
293 try:
294 output = None
295 if ip == "DEFAULT":
296 main.log.warn( "No ip given, reverting to ip from topo file" )
297 ip = self.ip_address
298 if port == "DEFAULT":
299 main.log.warn( "No port given, reverting to port" +
300 "from topo file" )
301 port = self.port
302 query = "/" + str( appName ) + "/active"
303 response = self.send( ip, port, method="DELETE",
304 url="/applications" + query )
305 if response:
306 output = response[ 1 ]
307 app = json.loads( output )
308 if 200 <= response[ 0 ] <= 299:
309 if check:
310 if app.get( 'state' ) == 'INSTALLED':
311 main.log.info( self.name + ": " + appName +
312 " application" +
313 " is in INSTALLED state" )
314 return main.TRUE
315 else:
316 main.log.error( self.name + ": " + appName +
317 " application" + " is in " +
318 app.get( 'state' ) + " state" )
319 return main.FALSE
320 else:
321 main.log.warn( "Skipping " + appName +
322 "application check" )
323 return main.TRUE
324 else:
325 main.log.error( "Error with REST request, response was: " +
326 str( response ) )
327 return main.FALSE
328 except Exception as e:
329 main.log.exception( e )
330 return None
331
332 def getApp( self, appName, project="org.onosproject.", ip="DEFAULT",
333 port="DEFAULT" ):
334 """
335 Decription:
336 Gets the informaion of the given application
337 Required:
338 str name - Name of onos application
339 Returns:
340 Returns a dictionary of information ONOS application in string type;
341 Returns main.FALSE if error on requests; Returns None for exception
342 """
343 try:
344 output = None
345 if ip == "DEFAULT":
346 main.log.warn( "No ip given, reverting to ip from topo file" )
347 ip = self.ip_address
348 if port == "DEFAULT":
349 main.log.warn( "No port given, reverting to port" +
350 "from topo file" )
351 port = self.port
352 query = "/" + project + str( appName )
353 response = self.send( ip, port, url="/applications" + query )
354 if response:
355 if 200 <= response[ 0 ] <= 299:
356 output = response[ 1 ]
357 a = json.loads( output )
358 return a
359 else:
360 main.log.error( "Error with REST request, response was: " +
361 str( response ) )
362 return main.FALSE
363 except Exception as e:
364 main.log.exception( e )
365 return None
366
367 def addHostIntent( self, hostIdOne, hostIdTwo, appId='org.onosproject.cli',
368 ip="DEFAULT", port="DEFAULT" ):
369 """
370 Description:
371 Adds a host-to-host intent ( bidirectional ) by
372 specifying the two hosts.
373 Required:
374 * hostIdOne: ONOS host id for host1
375 * hostIdTwo: ONOS host id for host2
376 Optional:
377 str appId - Application name of intent identifier
378 Returns:
379 A string of the intent id or None on Error; Returns main.FALSE if
380 error on requests; Returns None for exceptions
381 """
382 try:
383 intentJson = {"two": str( hostIdTwo ),
384 "selector": {"criteria": []}, "priority": 7,
385 "treatment": {"deferred": [], "instructions": []},
386 "appId": appId, "one": str( hostIdOne ),
387 "type": "HostToHostIntent",
388 "constraints": [{"type": "LinkTypeConstraint",
389 "types": ["OPTICAL"],
390 "inclusive": 'false' }]}
391 output = None
392 if ip == "DEFAULT":
393 main.log.warn( "No ip given, reverting to ip from topo file" )
394 ip = self.ip_address
395 if port == "DEFAULT":
396 main.log.warn( "No port given, reverting to port " +
397 "from topo file" )
398 port = self.port
399 response = self.send( ip,
400 port,
401 method="POST",
402 url="/intents",
403 data=json.dumps( intentJson ) )
404 if response:
405 if 201:
406 main.log.info( self.name + ": Successfully POST host" +
407 " intent between host: " + hostIdOne +
408 " and host: " + hostIdTwo )
409 return main.TRUE
410 else:
411 main.log.error( "Error with REST request, response was: " +
412 str( response ) )
413 return main.FALSE
414
415 except Exception as e:
416 main.log.exception( e )
417 return None
418
419
420 def removeIntent( self, intentId, appId='org.onosproject.cli',
421 ip="DEFAULT", port="DEFAULT" ):
422 """
423 Remove intent for specified application id and intent id;
424 Returns None for exception
425 """
426 try:
427 output = None
428 if ip == "DEFAULT":
429 main.log.warn( "No ip given, reverting to ip from topo file" )
430 ip = self.ip_address
431 if port == "DEFAULT":
432 main.log.warn( "No port given, reverting to port " +
433 "from topo file" )
434 port = self.port
435 # NOTE: REST url requires the intent id to be in decimal form
436 query = "/" + str( appId ) + "/" + str( int( intentId, 16 ) )
437 response = self.send( ip,
438 port,
439 method="DELETE",
440 url="/intents" + query )
441 if response:
442 if 200 <= response[ 0 ] <= 299:
443 return main.TRUE
444 else:
445 main.log.error( "Error with REST request, response was: " +
446 str( response ) )
447 return main.FALSE
448 except Exception as e:
449 main.log.exception( e )
450 return None
451
452 def getIntentsId( self, ip="DEFAULT", port="DEFAULT" ):
453 """
454 Returns a list of intents id; Returns None for exception
455 """
456 try:
457 intentIdList = []
458 intentsJson = json.loads( self.intents() )
459 print intentsJson
460 for intent in intentsJson:
461 intentIdList.append( intent.get( 'id' ) )
462 print intentIdList
463 return intentIdList
464 except Exception as e:
465 main.log.exception( e )
466 return None
467
468 def removeAllIntents( self, intentIdList ='ALL',appId='org.onosproject.cli',
469 ip="DEFAULT", port="DEFAULT", delay=5 ):
470 """
471 Description:
472 Remove all the intents
473 Returns:
474 Returns main.TRUE if all intents are removed, otherwise returns
475 main.FALSE; Returns None for exception
476 """
477 try:
478 results = []
479 if intentIdList == 'ALL':
480 intentIdList = self.getIntentsId( ip=ip, port=port )
481
482 main.log.info( self.name + ": Removing intents " +
483 str( intentIdList ) )
484
485 if isinstance( intentIdList, types.ListType ):
486 for intent in intentIdList:
487 results.append( self.removeIntent( intentId=intent,
488 appId=appId,
489 ip=ip,
490 port=port ) )
491 # Check for remaining intents
492 # NOTE: Noticing some delay on Deleting the intents so i put
493 # this time out
494 import time
495 time.sleep( delay )
496 intentRemain = len( json.loads( self.intents() ) )
497 if all( result==main.TRUE for result in results ) and \
498 intentRemain == 0:
499 main.log.info( self.name + ": All intents are removed " )
500 return main.TRUE
501 else:
502 main.log.error( self.name + ": Did not removed all intents,"
503 + " there are " + str( intentRemain )
504 + " intents remaining" )
505 return main.FALSE
506 else:
507 main.log.debug( self.name + ": There is no intents ID list" )
508 except Exception as e:
509 main.log.exception( e )
510 return None
511
512
513 def hosts( self, ip="DEFAULT", port="DEFAULT" ):
514 """
515 Description:
516 Get a list of dictionary of all discovered hosts
517 Returns:
518 Returns a list of dictionary of information of the hosts currently
519 discovered by ONOS; Returns main.FALSE if error on requests;
520 Returns None for exception
521 """
522 try:
523 output = None
524 if ip == "DEFAULT":
525 main.log.warn( "No ip given, reverting to ip from topo file" )
526 ip = self.ip_address
527 if port == "DEFAULT":
528 main.log.warn( "No port given, reverting to port \
529 from topo file" )
530 port = self.port
531 response = self.send( ip, port, url="/hosts" )
532 if response:
533 if 200 <= response[ 0 ] <= 299:
534 output = response[ 1 ]
535 a = json.loads( output ).get( 'hosts' )
536 b = json.dumps( a )
537 return b
538 else:
539 main.log.error( "Error with REST request, response was: " +
540 str( response ) )
541 return main.FALSE
542 except Exception as e:
543 main.log.exception( e )
544 return None
545
546 def getHost( self, mac, vlan="-1", ip="DEFAULT", port="DEFAULT" ):
547 """
548 Description:
549 Gets the information from the given host
550 Required:
551 str mac - MAC address of the host
552 Optional:
553 str vlan - VLAN tag of the host, defaults to -1
554 Returns:
555 Return the host id from the hosts/mac/vlan output in REST api
556 whose 'id' contains mac/vlan; Returns None for exception;
557 Returns main.FALSE if error on requests
558
559 NOTE:
560 Not sure what this function should do, any suggestion?
561 """
562 try:
563 output = None
564 if ip == "DEFAULT":
565 main.log.warn( "No ip given, reverting to ip from topo file" )
566 ip = self.ip_address
567 if port == "DEFAULT":
568 main.log.warn( "No port given, reverting to port \
569 from topo file" )
570 port = self.port
571 query = "/" + mac + "/" + vlan
572 response = self.send( ip, port, url="/hosts" + query )
573 if response:
574 # NOTE: What if the person wants other values? would it be better
575 # to have a function that gets a key and return a value instead?
576 # This function requires mac and vlan and returns an ID which
577 # makes this current function useless
578 if 200 <= response[ 0 ] <= 299:
579 output = response[ 1 ]
580 hostId = json.loads( output ).get( 'id' )
581 return hostId
582 else:
583 main.log.error( "Error with REST request, response was: " +
584 str( response ) )
585 return main.FALSE
586 except Exception as e:
587 main.log.exception( e )
588 return None
589
590 def topology( self, ip="DEFAULT", port="DEFAULT" ):
591 """
592 Description:
593 Gets the overview of network topology
594 Returns:
595 Returns a dictionary containing information about network topology;
596 Returns None for exception
597 """
598 try:
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, port, url="/topology" )
608 if response:
609 if 200 <= response[ 0 ] <= 299:
610 output = response[ 1 ]
611 a = json.loads( output )
612 b = json.dumps( a )
613 return b
614 else:
615 main.log.error( "Error with REST request, response was: " +
616 str( response ) )
617 return main.FALSE
618 except Exception as e:
619 main.log.exception( e )
620 return None
621
622 def getIntentState( self, intentsId, intentsJson=None,
623 ip="DEFAULT", port="DEFAULT" ):
624 """
625 Description:
626 Get intent state.
627 Accepts a single intent ID (string type) or a list of intent IDs.
628 Returns the state(string type) of the id if a single intent ID is
629 accepted.
630 Required:
631 intentId: intent ID (string type)
632 intentsJson: parsed json object from the onos:intents api
633 Returns:
634 Returns a dictionary with intent IDs as the key and its
635 corresponding states as the values; Returns None for invalid IDs or
636 Type error and any exceptions
637 NOTE:
638 An intent's state consist of INSTALLED,WITHDRAWN etc.
639 """
640 try:
641 state = "State is Undefined"
642 if not intentsJson:
643 intentsJsonTemp = json.loads( self.intents() )
644 else:
645 intentsJsonTemp = json.loads( intentsJson )
646 if isinstance( intentsId, types.StringType ):
647 for intent in intentsJsonTemp:
648 if intentsId == intent[ 'id' ]:
649 state = intent[ 'state' ]
650 return state
651 main.log.info( "Cannot find intent ID" + str( intentsId ) +
652 " on the list" )
653 return state
654 elif isinstance( intentsId, types.ListType ):
655 dictList = []
656 for i in xrange( len( intentsId ) ):
657 stateDict = {}
658 for intents in intentsJsonTemp:
659 if intentsId[ i ] == intents[ 'id' ]:
660 stateDict[ 'state' ] = intents[ 'state' ]
661 stateDict[ 'id' ] = intentsId[ i ]
662 dictList.append( stateDict )
663 break
664 if len( intentsId ) != len( dictList ):
665 main.log.info( "Cannot find some of the intent ID state" )
666 return dictList
667 else:
668 main.log.info( "Invalid intents ID entry" )
669 return None
670
671 except TypeError:
672 main.log.exception( self.name + ": Object Type not as expected" )
673 return None
674 except Exception as e:
675 main.log.exception( e )
676 return None
677
678 def checkIntentState( self, intentsId="ALL", expectedState='INSTALLED',
679 ip="DEFAULT", port="DEFAULT"):
680 """
681 Description:
682 Check intents state based on expected state which defaults to
683 INSTALLED state
684 Required:
685 intentsId - List of intents ID to be checked
686 Optional:
687 expectedState - Check the expected state(s) of each intents
688 state in the list.
689 *NOTE: You can pass in a list of expected state,
690 Eg: expectedState = [ 'INSTALLED' , 'INSTALLING' ]
691 Return:
692 Returns main.TRUE only if all intent are the same as expected states
693 , otherwise, returns main.FALSE; Returns None for general exception
694 """
695 try:
696 # Generating a dictionary: intent id as a key and state as value
697 returnValue = main.TRUE
698 if intentsId == "ALL":
699 intentsId = self.getIntentsId( ip=ip, port=port )
700 intentsDict = self.getIntentState( intentsId, ip=ip, port=port )
701
702 #print "len of intentsDict ", str( len( intentsDict ) )
703 if len( intentsId ) != len( intentsDict ):
704 main.log.error( self.name + ": There is something wrong " +
705 "getting intents state" )
706 return main.FALSE
707
708 if isinstance( expectedState, types.StringType ):
709 for intents in intentsDict:
710 if intents.get( 'state' ) != expectedState:
711 main.log.debug( self.name + " : Intent ID - " +
712 intents.get( 'id' ) +
713 " actual state = " +
714 intents.get( 'state' )
715 + " does not equal expected state = "
716 + expectedState )
717 returnValue = main.FALSE
718
719 elif isinstance( expectedState, types.ListType ):
720 for intents in intentsDict:
721 if not any( state == intents.get( 'state' ) for state in
722 expectedState ):
723 main.log.debug( self.name + " : Intent ID - " +
724 intents.get( 'id' ) +
725 " actual state = " +
726 intents.get( 'state' ) +
727 " does not equal expected states = "
728 + str( expectedState ) )
729 returnValue = main.FALSE
730
731 if returnValue == main.TRUE:
732 main.log.info( self.name + ": All " +
733 str( len( intentsDict ) ) +
734 " intents are in " + str( expectedState ) +
735 " state" )
736 return returnValue
737 except TypeError:
738 main.log.exception( self.name + ": Object not as expected" )
739 return main.FALSE
740 except Exception as e:
741 main.log.exception( e )
742 return None
743
744 def flows( self, ip="DEFAULT", port="DEFAULT" ):
745 """
746 Description:
747 Get flows currently added to the system
748 NOTE:
749 The flows -j cli command has completely different format than
750 the REST output; Returns None for exception
751 """
752 try:
753 output = None
754 if ip == "DEFAULT":
755 main.log.warn( "No ip given, reverting to ip from topo file" )
756 ip = self.ip_address
757 if port == "DEFAULT":
758 main.log.warn( "No port given, reverting to port \
759 from topo file" )
760 port = self.port
761 response = self.send( ip, port, url="/flows" )
762 if response:
763 if 200 <= response[ 0 ] <= 299:
764 output = response[ 1 ]
765 a = json.loads( output ).get( 'flows' )
766 b = json.dumps( a )
767 return b
768 else:
769 main.log.error( "Error with REST request, response was: " +
770 str( response ) )
771 return main.FALSE
772 except Exception as e:
773 main.log.exception( e )
774 return None
775
776 def checkFlowsState( self , ip="DEFAULT", port="DEFAULT" ):
777 """
778 Description:
779 Check if all the current flows are in ADDED state
780 Return:
781 returnValue - Returns main.TRUE only if all flows are in
782 return main.FALSE otherwise;
783 Returns None for exception
784 """
785 try:
786 tempFlows = json.loads( self.flows( ip=ip, port=port ) )
787 returnValue = main.TRUE
788 for flow in tempFlows:
789 if flow.get( 'state' ) != 'ADDED':
790 main.log.info( self.name + ": flow Id: " +
791 str( flow.get( 'groupId' ) ) +
792 " | state:" +
793 str( flow.get( 'state' ) ) )
794 returnValue = main.FALSE
795 return returnValue
796 except TypeError:
797 main.log.exception( self.name + ": Object not as expected" )
798 return main.FALSE
799 except Exception as e:
800 main.log.exception( e )
801 return None
802 except Exception:
803 main.log.exception( self.name + ": Uncaught exception!" )
804 main.cleanup()
805 main.exit()