blob: 15753a62277b9fd8c61fa9fb7105ab348de44bfa [file] [log] [blame]
Chetan Gaonker3ff8eae2016-04-12 14:50:26 -07001#!/usr/bin/env python
2
3"""
4This driver enters the onos> prompt to issue commands.
5
6Please follow the coding style demonstrated by existing
7functions and document properly.
8
9If you are a contributor to the driver, please
10list your email here for future contact:
11
12jhall@onlab.us
13andrew@onlab.us
14shreya@onlab.us
15
16OCT 13 2014
17
18"""
19import pexpect
20import re
21import json
22import types
23import time
24import os
25from clidriver import CLI
26from clicommon import *
27
28class OnosCliDriver( CLI ):
29
30 def __init__( self, controller = None, connect = True):
31 """
32 Initialize client
33 """
34 self.name = None
35 self.home = None
36 self.handle = None
37 self.controller = os.getenv('ONOS_CONTROLLER_IP') or 'localhost'
38 super( CLI, self ).__init__()
39 if connect == True:
40 self.connect_cli()
41
42 def connect_cli(self):
43 options = { 'name' : 'onoscli', 'onosIp': '{0}'.format(self.controller) }
44 self.connect(name = options['name'], user_name = 'onos', pwd = 'rocks',
45 ip_address = self.controller, port = '8101', options = options)
46
47 def connect( self, **connectargs ):
48 """
49 Creates ssh handle for ONOS cli.
50 """
51 try:
52 for key in connectargs:
53 vars( self )[ key ] = connectargs[ key ]
54 self.home = "~/onos"
55 for key in self.options:
56 if key == "home":
57 self.home = self.options[ 'home' ]
58 break
59 if self.home is None or self.home == "":
60 self.home = "~/onos"
61
62 for key in self.options:
63 if key == 'onosIp':
64 self.onosIp = self.options[ 'onosIp' ]
65 break
66
67 self.name = self.options[ 'name' ]
68
69 try:
70 if os.getenv( str( self.ip_address ) ) is not None:
71 self.ip_address = os.getenv( str( self.ip_address ) )
72 else:
73 main.log.info( self.name +
74 ": Trying to connect to " +
75 self.ip_address )
76
77 except KeyError:
78 main.log.info( "Invalid host name," +
79 " connecting to local host instead" )
80 self.ip_address = 'localhost'
81 except Exception as inst:
82 main.log.error( "Uncaught exception: " + str( inst ) )
83
84 self.handle = super( OnosCliDriver, self ).connect(
85 user_name=self.user_name,
86 ip_address=self.ip_address,
87 port=self.port,
88 pwd=self.pwd,
89 home=self.home )
90
91 #self.handle.sendline( "cd " + self.home )
92 #self.handle.expect( "\$" )
93 if self.handle:
94 return self.handle
95 else:
96 main.log.info( "NO ONOS HANDLE" )
97 return main.FALSE
98 except TypeError:
99 main.log.exception( self.name + ": Object not as expected" )
100 return None
101 except pexpect.EOF:
102 main.log.error( self.name + ": EOF exception found" )
103 main.log.error( self.name + ": " + self.handle.before )
104 main.cleanup()
105 main.exit()
106 except Exception:
107 main.log.exception( self.name + ": Uncaught exception!" )
108 main.cleanup()
109 main.exit()
110
111 def disconnect( self ):
112 """
113 Called when Test is complete to disconnect the ONOS handle.
114 """
115 response = main.TRUE
116 try:
117 if self.handle:
118 i = self.logout()
119 if i == main.TRUE:
120 self.handle.sendline( "" )
121 self.handle.expect( "\$" )
122 self.handle.sendline( "exit" )
123 self.handle.expect( "closed" )
124 except TypeError:
125 main.log.exception( self.name + ": Object not as expected" )
126 response = main.FALSE
127 except pexpect.EOF:
128 main.log.error( self.name + ": EOF exception found" )
129 main.log.error( self.name + ": " + self.handle.before )
130 except ValueError:
131 main.log.exception( "Exception in disconnect of " + self.name )
132 response = main.TRUE
133 except Exception:
134 main.log.exception( self.name + ": Connection failed to the host" )
135 response = main.FALSE
136 return response
137
138 def logout( self ):
139 """
140 Sends 'logout' command to ONOS cli
141 Returns main.TRUE if exited CLI and
142 main.FALSE on timeout (not guranteed you are disconnected)
143 None on TypeError
144 Exits test on unknown error or pexpect exits unexpectedly
145 """
146 try:
147 if self.handle:
148 self.handle.sendline( "" )
149 i = self.handle.expect( [ "onos>", "\$", pexpect.TIMEOUT ],
150 timeout=10 )
151 if i == 0: # In ONOS CLI
152 self.handle.sendline( "logout" )
153 j = self.handle.expect( [ "\$",
154 "Command not found:",
155 pexpect.TIMEOUT ] )
156 if j == 0: # Successfully logged out
157 return main.TRUE
158 elif j == 1 or j == 2:
159 # ONOS didn't fully load, and logout command isn't working
160 # or the command timed out
161 self.handle.send( "\x04" ) # send ctrl-d
162 self.handle.expect( "\$" )
163 return main.TRUE
164 else: # some other output
165 main.log.warn( "Unknown repsonse to logout command: '{}'",
166 repr( self.handle.before ) )
167 return main.FALSE
168 elif i == 1: # not in CLI
169 return main.TRUE
170 elif i == 3: # Timeout
171 return main.FALSE
172 else:
173 return main.TRUE
174 except TypeError:
175 main.log.exception( self.name + ": Object not as expected" )
176 return None
177 except pexpect.EOF:
178 main.log.error( self.name + ": eof exception found" )
179 main.log.error( self.name + ": " + self.handle.before )
180 main.cleanup()
181 main.exit()
182 except ValueError:
183 main.log.error( self.name +
184 "ValueError exception in logout method" )
185 except Exception:
186 main.log.exception( self.name + ": Uncaught exception!" )
187 main.cleanup()
188 main.exit()
189
190 def setCell( self, cellname ):
191 """
192 Calls 'cell <name>' to set the environment variables on ONOSbench
193
194 Before issuing any cli commands, set the environment variable first.
195 """
196 try:
197 if not cellname:
198 main.log.error( "Must define cellname" )
199 main.cleanup()
200 main.exit()
201 else:
202 self.handle.sendline( "cell " + str( cellname ) )
203 # Expect the cellname in the ONOSCELL variable.
204 # Note that this variable name is subject to change
205 # and that this driver will have to change accordingly
206 self.handle.expect(str(cellname))
207 handleBefore = self.handle.before
208 handleAfter = self.handle.after
209 # Get the rest of the handle
210 self.handle.sendline("")
211 self.handle.expect("\$")
212 handleMore = self.handle.before
213
214 main.log.info( "Cell call returned: " + handleBefore +
215 handleAfter + handleMore )
216
217 return main.TRUE
218
219 except TypeError:
220 main.log.exception( self.name + ": Object not as expected" )
221 return None
222 except pexpect.EOF:
223 main.log.error( self.name + ": eof exception found" )
224 main.log.error( self.name + ": " + self.handle.before )
225 main.cleanup()
226 main.exit()
227 except Exception:
228 main.log.exception( self.name + ": Uncaught exception!" )
229 main.cleanup()
230 main.exit()
231
232 def startOnosCli( self, ONOSIp, karafTimeout="",
233 commandlineTimeout=10, onosStartTimeout=60 ):
234 """
235 karafTimeout is an optional argument. karafTimeout value passed
236 by user would be used to set the current karaf shell idle timeout.
237 Note that when ever this property is modified the shell will exit and
238 the subsequent login would reflect new idle timeout.
239 Below is an example to start a session with 60 seconds idle timeout
240 ( input value is in milliseconds ):
241
242 tValue = "60000"
243 main.ONOScli1.startOnosCli( ONOSIp, karafTimeout=tValue )
244
245 Note: karafTimeout is left as str so that this could be read
246 and passed to startOnosCli from PARAMS file as str.
247 """
248 self.onosIp = ONOSIp
249 try:
250 self.handle.sendline( "" )
251 x = self.handle.expect( [
252 "\$", "onos>" ], commandlineTimeout)
253
254 if x == 1:
255 main.log.info( "ONOS cli is already running" )
256 return main.TRUE
257
258 # Wait for onos start ( -w ) and enter onos cli
259 self.handle.sendline( "onos -w " + str( ONOSIp ) )
260 i = self.handle.expect( [
261 "onos>",
262 pexpect.TIMEOUT ], onosStartTimeout )
263
264 if i == 0:
265 main.log.info( str( ONOSIp ) + " CLI Started successfully" )
266 if karafTimeout:
267 self.handle.sendline(
268 "config:property-set -p org.apache.karaf.shell\
269 sshIdleTimeout " +
270 karafTimeout )
271 self.handle.expect( "\$" )
272 self.handle.sendline( "onos -w " + str( ONOSIp ) )
273 self.handle.expect( "onos>" )
274 return main.TRUE
275 else:
276 # If failed, send ctrl+c to process and try again
277 main.log.info( "Starting CLI failed. Retrying..." )
278 self.handle.send( "\x03" )
279 self.handle.sendline( "onos -w " + str( ONOSIp ) )
280 i = self.handle.expect( [ "onos>", pexpect.TIMEOUT ],
281 timeout=30 )
282 if i == 0:
283 main.log.info( str( ONOSIp ) + " CLI Started " +
284 "successfully after retry attempt" )
285 if karafTimeout:
286 self.handle.sendline(
287 "config:property-set -p org.apache.karaf.shell\
288 sshIdleTimeout " +
289 karafTimeout )
290 self.handle.expect( "\$" )
291 self.handle.sendline( "onos -w " + str( ONOSIp ) )
292 self.handle.expect( "onos>" )
293 return main.TRUE
294 else:
295 main.log.error( "Connection to CLI " +
296 str( ONOSIp ) + " timeout" )
297 return main.FALSE
298
299 except TypeError:
300 main.log.exception( self.name + ": Object not as expected" )
301 return None
302 except pexpect.EOF:
303 main.log.error( self.name + ": EOF exception found" )
304 main.log.error( self.name + ": " + self.handle.before )
305 main.cleanup()
306 main.exit()
307 except Exception:
308 main.log.exception( self.name + ": Uncaught exception!" )
309 main.cleanup()
310 main.exit()
311
312 def log( self, cmdStr, level="" ):
313 """
314 log the commands in the onos CLI.
315 returns main.TRUE on success
316 returns main.FALSE if Error occurred
317 Available level: DEBUG, TRACE, INFO, WARN, ERROR
318 Level defaults to INFO
319 """
320 try:
321 lvlStr = ""
322 if level:
323 lvlStr = "--level=" + level
324
325 self.handle.sendline( "" )
326 i = self.handle.expect( [ "onos>", "\$", pexpect.TIMEOUT ] )
327 if i == 1:
328 main.log.error( self.name + ": onos cli session closed. ")
329 if self.onosIp:
330 main.log.warn( "Trying to reconnect " + self.onosIp )
331 reconnectResult = self.startOnosCli( self.onosIp )
332 if reconnectResult:
333 main.log.info( self.name + ": onos cli session reconnected." )
334 else:
335 main.log.error( self.name + ": reconnection failed." )
336 main.cleanup()
337 main.exit()
338 else:
339 main.cleanup()
340 main.exit()
341 if i == 2:
342 self.handle.sendline( "" )
343 self.handle.expect( "onos>" )
344 self.handle.sendline( "log:log " + lvlStr + " " + cmdStr )
345 self.handle.expect( "log:log" )
346 self.handle.expect( "onos>" )
347
348 response = self.handle.before
349 if re.search( "Error", response ):
350 return main.FALSE
351 return main.TRUE
352 except pexpect.TIMEOUT:
353 main.log.exception( self.name + ": TIMEOUT exception found" )
354 main.cleanup()
355 main.exit()
356 except pexpect.EOF:
357 main.log.error( self.name + ": EOF exception found" )
358 main.log.error( self.name + ": " + self.handle.before )
359 main.cleanup()
360 main.exit()
361 except Exception:
362 main.log.exception( self.name + ": Uncaught exception!" )
363 main.cleanup()
364 main.exit()
365
366 def sendline( self, cmdStr, showResponse=False, debug=False, timeout=10 ):
367 """
368 Send a completely user specified string to
369 the onos> prompt. Use this function if you have
370 a very specific command to send.
371
372 Warning: There are no sanity checking to commands
373 sent using this method.
374
375 """
376 try:
377 logStr = "\"Sending CLI command: '" + cmdStr + "'\""
378 self.log( logStr )
379 self.handle.sendline( cmdStr )
380 i = self.handle.expect( ["onos>", "\$"], timeout )
381 response = self.handle.before
382 # TODO: do something with i
383 main.log.info( "Command '" + str( cmdStr ) + "' sent to "
384 + self.name + "." )
385 if debug:
386 main.log.debug( self.name + ": Raw output" )
387 main.log.debug( self.name + ": " + repr( response ) )
388
389 # Remove ANSI color control strings from output
390 ansiEscape = re.compile( r'\x1b[^m]*m' )
391 response = ansiEscape.sub( '', response )
392 if debug:
393 main.log.debug( self.name + ": ansiEscape output" )
394 main.log.debug( self.name + ": " + repr( response ) )
395
396 # Remove extra return chars that get added
397 response = re.sub( r"\s\r", "", response )
398 if debug:
399 main.log.debug( self.name + ": Removed extra returns " +
400 "from output" )
401 main.log.debug( self.name + ": " + repr( response ) )
402
403 # Strip excess whitespace
404 response = response.strip()
405 if debug:
406 main.log.debug( self.name + ": parsed and stripped output" )
407 main.log.debug( self.name + ": " + repr( response ) )
408
409 # parse for just the output, remove the cmd from response
410 output = response.split( cmdStr.strip(), 1 )
411 if debug:
412 main.log.debug( self.name + ": split output" )
413 for r in output:
414 main.log.debug( self.name + ": " + repr( r ) )
415 output = output[1].strip()
416 if showResponse:
417 main.log.info( "Response from ONOS: {}".format( output ) )
418 return output
419 except pexpect.TIMEOUT:
420 main.log.error( self.name + ":ONOS timeout" )
421 if debug:
422 main.log.debug( self.handle.before )
423 return None
424 except IndexError:
425 main.log.exception( self.name + ": Object not as expected" )
426 return None
427 except TypeError:
428 main.log.exception( self.name + ": Object not as expected" )
429 return None
430 except pexpect.EOF:
431 main.log.error( self.name + ": EOF exception found" )
432 main.log.error( self.name + ": " + self.handle.before )
433 main.cleanup()
434 main.exit()
435 except Exception:
436 main.log.exception( self.name + ": Uncaught exception!" )
437 main.cleanup()
438 main.exit()
439
440 # IMPORTANT NOTE:
441 # For all cli commands, naming convention should match
442 # the cli command changing 'a:b' with 'aB'.
443 # Ex ) onos:topology > onosTopology
444 # onos:links > onosLinks
445 # feature:list > featureList
446
447 def addNode( self, nodeId, ONOSIp, tcpPort="" ):
448 """
449 Adds a new cluster node by ID and address information.
450 Required:
451 * nodeId
452 * ONOSIp
453 Optional:
454 * tcpPort
455 """
456 try:
457 cmdStr = "add-node " + str( nodeId ) + " " +\
458 str( ONOSIp ) + " " + str( tcpPort )
459 handle = self.sendline( cmdStr )
460 assert "Command not found:" not in handle, handle
461 if re.search( "Error", handle ):
462 main.log.error( "Error in adding node" )
463 main.log.error( handle )
464 return main.FALSE
465 else:
466 main.log.info( "Node " + str( ONOSIp ) + " added" )
467 return main.TRUE
468 except AssertionError:
469 main.log.exception( "" )
470 return None
471 except TypeError:
472 main.log.exception( self.name + ": Object not as expected" )
473 return None
474 except pexpect.EOF:
475 main.log.error( self.name + ": EOF exception found" )
476 main.log.error( self.name + ": " + self.handle.before )
477 main.cleanup()
478 main.exit()
479 except Exception:
480 main.log.exception( self.name + ": Uncaught exception!" )
481 main.cleanup()
482 main.exit()
483
484 def removeNode( self, nodeId ):
485 """
486 Removes a cluster by ID
487 Issues command: 'remove-node [<node-id>]'
488 Required:
489 * nodeId
490 """
491 try:
492
493 cmdStr = "remove-node " + str( nodeId )
494 handle = self.sendline( cmdStr )
495 assert "Command not found:" not in handle, handle
496 if re.search( "Error", handle ):
497 main.log.error( "Error in removing node" )
498 main.log.error( handle )
499 return main.FALSE
500 else:
501 return main.TRUE
502 except AssertionError:
503 main.log.exception( "" )
504 return None
505 except TypeError:
506 main.log.exception( self.name + ": Object not as expected" )
507 return None
508 except pexpect.EOF:
509 main.log.error( self.name + ": EOF exception found" )
510 main.log.error( self.name + ": " + self.handle.before )
511 main.cleanup()
512 main.exit()
513 except Exception:
514 main.log.exception( self.name + ": Uncaught exception!" )
515 main.cleanup()
516 main.exit()
517
518 def nodes( self, jsonFormat=True):
519 """
520 List the nodes currently visible
521 Issues command: 'nodes'
522 Optional argument:
523 * jsonFormat - boolean indicating if you want output in json
524 """
525 try:
526 cmdStr = "nodes"
527 if jsonFormat:
528 cmdStr += " -j"
529 output = self.sendline( cmdStr )
530 assert "Command not found:" not in output, output
531 return output
532 except AssertionError:
533 main.log.exception( "" )
534 return None
535 except TypeError:
536 main.log.exception( self.name + ": Object not as expected" )
537 return None
538 except pexpect.EOF:
539 main.log.error( self.name + ": EOF exception found" )
540 main.log.error( self.name + ": " + self.handle.before )
541 main.cleanup()
542 main.exit()
543 except Exception:
544 main.log.exception( self.name + ": Uncaught exception!" )
545 main.cleanup()
546 main.exit()
547
548 def topology( self ):
549 """
550 Definition:
551 Returns the output of topology command.
552 Return:
553 topology = current ONOS topology
554 """
555 try:
556 cmdStr = "topology -j"
557 handle = self.sendline( cmdStr )
558 assert "Command not found:" not in handle, handle
559 main.log.info( cmdStr + " returned: " + str( handle ) )
560 return handle
561 except AssertionError:
562 main.log.exception( "" )
563 return None
564 except TypeError:
565 main.log.exception( self.name + ": Object not as expected" )
566 return None
567 except pexpect.EOF:
568 main.log.error( self.name + ": EOF exception found" )
569 main.log.error( self.name + ": " + self.handle.before )
570 main.cleanup()
571 main.exit()
572 except Exception:
573 main.log.exception( self.name + ": Uncaught exception!" )
574 main.cleanup()
575 main.exit()
576
577 def deviceRemove( self, deviceId ):
578 """
579 Removes particular device from storage
580
581 TODO: refactor this function
582 """
583 try:
584 cmdStr = "device-remove " + str( deviceId )
585 handle = self.sendline( cmdStr )
586 assert "Command not found:" not in handle, handle
587 if re.search( "Error", handle ):
588 main.log.error( "Error in removing device" )
589 main.log.error( handle )
590 return main.FALSE
591 else:
592 return main.TRUE
593 except AssertionError:
594 main.log.exception( "" )
595 return None
596 except TypeError:
597 main.log.exception( self.name + ": Object not as expected" )
598 return None
599 except pexpect.EOF:
600 main.log.error( self.name + ": EOF exception found" )
601 main.log.error( self.name + ": " + self.handle.before )
602 main.cleanup()
603 main.exit()
604 except Exception:
605 main.log.exception( self.name + ": Uncaught exception!" )
606 main.cleanup()
607 main.exit()
608
609 def devices( self, jsonFormat=True ):
610 """
611 Lists all infrastructure devices or switches
612 Optional argument:
613 * jsonFormat - boolean indicating if you want output in json
614 """
615 try:
616 cmdStr = "devices"
617 if jsonFormat:
618 cmdStr += " -j"
619 handle = self.sendline( cmdStr )
620 assert "Command not found:" not in handle, handle
621 return handle
622 except AssertionError:
623 main.log.exception( "" )
624 return None
625 except TypeError:
626 main.log.exception( self.name + ": Object not as expected" )
627 return None
628 except pexpect.EOF:
629 main.log.error( self.name + ": EOF exception found" )
630 main.log.error( self.name + ": " + self.handle.before )
631 main.cleanup()
632 main.exit()
633 except Exception:
634 main.log.exception( self.name + ": Uncaught exception!" )
635 main.cleanup()
636 main.exit()
637
638 def balanceMasters( self ):
639 """
640 This balances the devices across all controllers
641 by issuing command: 'onos> onos:balance-masters'
642 If required this could be extended to return devices balanced output.
643 """
644 try:
645 cmdStr = "onos:balance-masters"
646 handle = self.sendline( cmdStr )
647 assert "Command not found:" not in handle, handle
648 if re.search( "Error", handle ):
649 main.log.error( "Error in balancing masters" )
650 main.log.error( handle )
651 return main.FALSE
652 else:
653 return main.TRUE
654 except AssertionError:
655 main.log.exception( "" )
656 return None
657 except TypeError:
658 main.log.exception( self.name + ": Object not as expected" )
659 return None
660 except pexpect.EOF:
661 main.log.error( self.name + ": EOF exception found" )
662 main.log.error( self.name + ": " + self.handle.before )
663 main.cleanup()
664 main.exit()
665 except Exception:
666 main.log.exception( self.name + ": Uncaught exception!" )
667 main.cleanup()
668 main.exit()
669
670 def checkMasters( self, jsonFormat=True ):
671 """
672 Returns the output of the masters command.
673 Optional argument:
674 * jsonFormat - boolean indicating if you want output in json
675 """
676 try:
677 cmdStr = "onos:masters"
678 if jsonFormat:
679 cmdStr += " -j"
680 output = self.sendline( cmdStr )
681 assert "Command not found:" not in output, output
682 return output
683 except AssertionError:
684 main.log.exception( "" )
685 return None
686 except TypeError:
687 main.log.exception( self.name + ": Object not as expected" )
688 return None
689 except pexpect.EOF:
690 main.log.error( self.name + ": EOF exception found" )
691 main.log.error( self.name + ": " + self.handle.before )
692 main.cleanup()
693 main.exit()
694 except Exception:
695 main.log.exception( self.name + ": Uncaught exception!" )
696 main.cleanup()
697 main.exit()
698
699 def checkBalanceMasters( self, jsonFormat=True ):
700 """
701 Uses the master command to check that the devices' leadership
702 is evenly divided
703
704 Dependencies: checkMasters() and summary()
705
706 Returns main.True if the devices are balanced
707 Returns main.False if the devices are unbalanced
708 Exits on Exception
709 Returns None on TypeError
710 """
711 try:
712 summaryOutput = self.summary()
713 totalDevices = json.loads( summaryOutput )[ "devices" ]
714 except ( TypeError, ValueError ):
715 main.log.exception( "{}: Object not as expected: {!r}".format( self.name, summaryOutput ) )
716 return None
717 try:
718 totalOwnedDevices = 0
719 mastersOutput = self.checkMasters()
720 masters = json.loads( mastersOutput )
721 first = masters[ 0 ][ "size" ]
722 for master in masters:
723 totalOwnedDevices += master[ "size" ]
724 if master[ "size" ] > first + 1 or master[ "size" ] < first - 1:
725 main.log.error( "Mastership not balanced" )
726 main.log.info( "\n" + self.checkMasters( False ) )
727 return main.FALSE
728 main.log.info( "Mastership balanced between " \
729 + str( len(masters) ) + " masters" )
730 return main.TRUE
731 except ( TypeError, ValueError ):
732 main.log.exception( "{}: Object not as expected: {!r}".format( self.name, mastersOutput ) )
733 return None
734 except pexpect.EOF:
735 main.log.error( self.name + ": EOF exception found" )
736 main.log.error( self.name + ": " + self.handle.before )
737 main.cleanup()
738 main.exit()
739 except Exception:
740 main.log.exception( self.name + ": Uncaught exception!" )
741 main.cleanup()
742 main.exit()
743
744 def links( self, jsonFormat=True ):
745 """
746 Lists all core links
747 Optional argument:
748 * jsonFormat - boolean indicating if you want output in json
749 """
750 try:
751 cmdStr = "links"
752 if jsonFormat:
753 cmdStr += " -j"
754 handle = self.sendline( cmdStr )
755 assert "Command not found:" not in handle, handle
756 return handle
757 except AssertionError:
758 main.log.exception( "" )
759 return None
760 except TypeError:
761 main.log.exception( self.name + ": Object not as expected" )
762 return None
763 except pexpect.EOF:
764 main.log.error( self.name + ": EOF exception found" )
765 main.log.error( self.name + ": " + self.handle.before )
766 main.cleanup()
767 main.exit()
768 except Exception:
769 main.log.exception( self.name + ": Uncaught exception!" )
770 main.cleanup()
771 main.exit()
772
773 def ports( self, jsonFormat=True ):
774 """
775 Lists all ports
776 Optional argument:
777 * jsonFormat - boolean indicating if you want output in json
778 """
779 try:
780 cmdStr = "ports"
781 if jsonFormat:
782 cmdStr += " -j"
783 handle = self.sendline( cmdStr )
784 assert "Command not found:" not in handle, handle
785 return handle
786 except AssertionError:
787 main.log.exception( "" )
788 return None
789 except TypeError:
790 main.log.exception( self.name + ": Object not as expected" )
791 return None
792 except pexpect.EOF:
793 main.log.error( self.name + ": EOF exception found" )
794 main.log.error( self.name + ": " + self.handle.before )
795 main.cleanup()
796 main.exit()
797 except Exception:
798 main.log.exception( self.name + ": Uncaught exception!" )
799 main.cleanup()
800 main.exit()
801
802 def roles( self, jsonFormat=True ):
803 """
804 Lists all devices and the controllers with roles assigned to them
805 Optional argument:
806 * jsonFormat - boolean indicating if you want output in json
807 """
808 try:
809 cmdStr = "roles"
810 if jsonFormat:
811 cmdStr += " -j"
812 handle = self.sendline( cmdStr )
813 assert "Command not found:" not in handle, handle
814 return handle
815 except AssertionError:
816 main.log.exception( "" )
817 return None
818 except TypeError:
819 main.log.exception( self.name + ": Object not as expected" )
820 return None
821 except pexpect.EOF:
822 main.log.error( self.name + ": EOF exception found" )
823 main.log.error( self.name + ": " + self.handle.before )
824 main.cleanup()
825 main.exit()
826 except Exception:
827 main.log.exception( self.name + ": Uncaught exception!" )
828 main.cleanup()
829 main.exit()
830
831 def getRole( self, deviceId ):
832 """
833 Given the a string containing the json representation of the "roles"
834 cli command and a partial or whole device id, returns a json object
835 containing the roles output for the first device whose id contains
836 "device_id"
837
838 Returns:
839 A dict of the role assignments for the given device or
840 None if no match
841 """
842 try:
843 if deviceId is None:
844 return None
845 else:
846 rawRoles = self.roles()
847 rolesJson = json.loads( rawRoles )
848 # search json for the device with id then return the device
849 for device in rolesJson:
850 # print device
851 if str( deviceId ) in device[ 'id' ]:
852 return device
853 return None
854 except ( TypeError, ValueError ):
855 main.log.exception( "{}: Object not as expected: {!r}".format( self.name, rawRoles ) )
856 return None
857 except pexpect.EOF:
858 main.log.error( self.name + ": EOF exception found" )
859 main.log.error( self.name + ": " + self.handle.before )
860 main.cleanup()
861 main.exit()
862 except Exception:
863 main.log.exception( self.name + ": Uncaught exception!" )
864 main.cleanup()
865 main.exit()
866
867 def rolesNotNull( self ):
868 """
869 Iterates through each device and checks if there is a master assigned
870 Returns: main.TRUE if each device has a master
871 main.FALSE any device has no master
872 """
873 try:
874 rawRoles = self.roles()
875 rolesJson = json.loads( rawRoles )
876 # search json for the device with id then return the device
877 for device in rolesJson:
878 # print device
879 if device[ 'master' ] == "none":
880 main.log.warn( "Device has no master: " + str( device ) )
881 return main.FALSE
882 return main.TRUE
883 except ( TypeError, ValueError ):
884 main.log.exception( "{}: Object not as expected: {!r}".format( self.name, rawRoles ) )
885 return None
886 except pexpect.EOF:
887 main.log.error( self.name + ": EOF exception found" )
888 main.log.error( self.name + ": " + self.handle.before )
889 main.cleanup()
890 main.exit()
891 except Exception:
892 main.log.exception( self.name + ": Uncaught exception!" )
893 main.cleanup()
894 main.exit()
895
896 def paths( self, srcId, dstId ):
897 """
898 Returns string of paths, and the cost.
899 Issues command: onos:paths <src> <dst>
900 """
901 try:
902 cmdStr = "onos:paths " + str( srcId ) + " " + str( dstId )
903 handle = self.sendline( cmdStr )
904 assert "Command not found:" not in handle, handle
905 if re.search( "Error", handle ):
906 main.log.error( "Error in getting paths" )
907 return ( handle, "Error" )
908 else:
909 path = handle.split( ";" )[ 0 ]
910 cost = handle.split( ";" )[ 1 ]
911 return ( path, cost )
912 except AssertionError:
913 main.log.exception( "" )
914 return ( handle, "Error" )
915 except TypeError:
916 main.log.exception( self.name + ": Object not as expected" )
917 return ( handle, "Error" )
918 except pexpect.EOF:
919 main.log.error( self.name + ": EOF exception found" )
920 main.log.error( self.name + ": " + self.handle.before )
921 main.cleanup()
922 main.exit()
923 except Exception:
924 main.log.exception( self.name + ": Uncaught exception!" )
925 main.cleanup()
926 main.exit()
927
928 def hosts( self, jsonFormat=True ):
929 """
930 Lists all discovered hosts
931 Optional argument:
932 * jsonFormat - boolean indicating if you want output in json
933 """
934 try:
935 cmdStr = "hosts"
936 if jsonFormat:
937 cmdStr += " -j"
938 handle = self.sendline( cmdStr )
939 assert "Command not found:" not in handle, handle
940 try:
941 # TODO: Maybe make this less hardcoded
942 # ConsistentMap Exceptions
943 assert "org.onosproject.store.service" not in handle
944 # Node not leader
945 assert "java.lang.IllegalStateException" not in handle
946 except AssertionError:
947 main.log.error( "Error in processing '" + cmdStr + "' " +
948 "command: " + str( handle ) )
949 return None
950 return handle
951 except AssertionError:
952 main.log.exception( "" )
953 return None
954 except TypeError:
955 main.log.exception( self.name + ": Object not as expected" )
956 return None
957 except pexpect.EOF:
958 main.log.error( self.name + ": EOF exception found" )
959 main.log.error( self.name + ": " + self.handle.before )
960 main.cleanup()
961 main.exit()
962 except Exception:
963 main.log.exception( self.name + ": Uncaught exception!" )
964 main.cleanup()
965 main.exit()
966
967 def getHost( self, mac ):
968 """
969 Return the first host from the hosts api whose 'id' contains 'mac'
970
971 Note: mac must be a colon separated mac address, but could be a
972 partial mac address
973
974 Return None if there is no match
975 """
976 try:
977 if mac is None:
978 return None
979 else:
980 mac = mac
981 rawHosts = self.hosts()
982 hostsJson = json.loads( rawHosts )
983 # search json for the host with mac then return the device
984 for host in hostsJson:
985 # print "%s in %s?" % ( mac, host[ 'id' ] )
986 if not host:
987 pass
988 elif mac in host[ 'id' ]:
989 return host
990 return None
991 except ( TypeError, ValueError ):
992 main.log.exception( "{}: Object not as expected: {!r}".format( self.name, rawHosts ) )
993 return None
994 except pexpect.EOF:
995 main.log.error( self.name + ": EOF exception found" )
996 main.log.error( self.name + ": " + self.handle.before )
997 main.cleanup()
998 main.exit()
999 except Exception:
1000 main.log.exception( self.name + ": Uncaught exception!" )
1001 main.cleanup()
1002 main.exit()
1003
1004 def getHostsId( self, hostList ):
1005 """
1006 Obtain list of hosts
1007 Issues command: 'onos> hosts'
1008
1009 Required:
1010 * hostList: List of hosts obtained by Mininet
1011 IMPORTANT:
1012 This function assumes that you started your
1013 topology with the option '--mac'.
1014 Furthermore, it assumes that value of VLAN is '-1'
1015 Description:
1016 Converts mininet hosts ( h1, h2, h3... ) into
1017 ONOS format ( 00:00:00:00:00:01/-1 , ... )
1018 """
1019 try:
1020 onosHostList = []
1021
1022 for host in hostList:
1023 host = host.replace( "h", "" )
1024 hostHex = hex( int( host ) ).zfill( 12 )
1025 hostHex = str( hostHex ).replace( 'x', '0' )
1026 i = iter( str( hostHex ) )
1027 hostHex = ":".join( a + b for a, b in zip( i, i ) )
1028 hostHex = hostHex + "/-1"
1029 onosHostList.append( hostHex )
1030
1031 return onosHostList
1032
1033 except TypeError:
1034 main.log.exception( self.name + ": Object not as expected" )
1035 return None
1036 except pexpect.EOF:
1037 main.log.error( self.name + ": EOF exception found" )
1038 main.log.error( self.name + ": " + self.handle.before )
1039 main.cleanup()
1040 main.exit()
1041 except Exception:
1042 main.log.exception( self.name + ": Uncaught exception!" )
1043 main.cleanup()
1044 main.exit()
1045
1046 def addHostIntent( self, hostIdOne, hostIdTwo ):
1047 """
1048 Required:
1049 * hostIdOne: ONOS host id for host1
1050 * hostIdTwo: ONOS host id for host2
1051 Description:
1052 Adds a host-to-host intent ( bidirectional ) by
1053 specifying the two hosts.
1054 Returns:
1055 A string of the intent id or None on Error
1056 """
1057 try:
1058 cmdStr = "add-host-intent " + str( hostIdOne ) +\
1059 " " + str( hostIdTwo )
1060 handle = self.sendline( cmdStr )
1061 assert "Command not found:" not in handle, handle
1062 if re.search( "Error", handle ):
1063 main.log.error( "Error in adding Host intent" )
1064 main.log.debug( "Response from ONOS was: " + repr( handle ) )
1065 return None
1066 else:
1067 main.log.info( "Host intent installed between " +
1068 str( hostIdOne ) + " and " + str( hostIdTwo ) )
1069 match = re.search('id=0x([\da-f]+),', handle)
1070 if match:
1071 return match.group()[3:-1]
1072 else:
1073 main.log.error( "Error, intent ID not found" )
1074 main.log.debug( "Response from ONOS was: " +
1075 repr( handle ) )
1076 return None
1077 except AssertionError:
1078 main.log.exception( "" )
1079 return None
1080 except TypeError:
1081 main.log.exception( self.name + ": Object not as expected" )
1082 return None
1083 except pexpect.EOF:
1084 main.log.error( self.name + ": EOF exception found" )
1085 main.log.error( self.name + ": " + self.handle.before )
1086 main.cleanup()
1087 main.exit()
1088 except Exception:
1089 main.log.exception( self.name + ": Uncaught exception!" )
1090 main.cleanup()
1091 main.exit()
1092
1093 def addOpticalIntent( self, ingressDevice, egressDevice ):
1094 """
1095 Required:
1096 * ingressDevice: device id of ingress device
1097 * egressDevice: device id of egress device
1098 Optional:
1099 TODO: Still needs to be implemented via dev side
1100 Description:
1101 Adds an optical intent by specifying an ingress and egress device
1102 Returns:
1103 A string of the intent id or None on error
1104 """
1105 try:
1106 cmdStr = "add-optical-intent " + str( ingressDevice ) +\
1107 " " + str( egressDevice )
1108 handle = self.sendline( cmdStr )
1109 assert "Command not found:" not in handle, handle
1110 # If error, return error message
1111 if re.search( "Error", handle ):
1112 main.log.error( "Error in adding Optical intent" )
1113 return None
1114 else:
1115 main.log.info( "Optical intent installed between " +
1116 str( ingressDevice ) + " and " +
1117 str( egressDevice ) )
1118 match = re.search('id=0x([\da-f]+),', handle)
1119 if match:
1120 return match.group()[3:-1]
1121 else:
1122 main.log.error( "Error, intent ID not found" )
1123 return None
1124 except AssertionError:
1125 main.log.exception( "" )
1126 return None
1127 except TypeError:
1128 main.log.exception( self.name + ": Object not as expected" )
1129 return None
1130 except pexpect.EOF:
1131 main.log.error( self.name + ": EOF exception found" )
1132 main.log.error( self.name + ": " + self.handle.before )
1133 main.cleanup()
1134 main.exit()
1135 except Exception:
1136 main.log.exception( self.name + ": Uncaught exception!" )
1137 main.cleanup()
1138 main.exit()
1139
1140 def addPointIntent(
1141 self,
1142 ingressDevice,
1143 egressDevice,
1144 portIngress="",
1145 portEgress="",
1146 ethType="",
1147 ethSrc="",
1148 ethDst="",
1149 bandwidth="",
1150 lambdaAlloc=False,
1151 ipProto="",
1152 ipSrc="",
1153 ipDst="",
1154 tcpSrc="",
1155 tcpDst="" ):
1156 """
1157 Required:
1158 * ingressDevice: device id of ingress device
1159 * egressDevice: device id of egress device
1160 Optional:
1161 * ethType: specify ethType
1162 * ethSrc: specify ethSrc ( i.e. src mac addr )
1163 * ethDst: specify ethDst ( i.e. dst mac addr )
1164 * bandwidth: specify bandwidth capacity of link
1165 * lambdaAlloc: if True, intent will allocate lambda
1166 for the specified intent
1167 * ipProto: specify ip protocol
1168 * ipSrc: specify ip source address
1169 * ipDst: specify ip destination address
1170 * tcpSrc: specify tcp source port
1171 * tcpDst: specify tcp destination port
1172 Description:
1173 Adds a point-to-point intent ( uni-directional ) by
1174 specifying device id's and optional fields
1175 Returns:
1176 A string of the intent id or None on error
1177
1178 NOTE: This function may change depending on the
1179 options developers provide for point-to-point
1180 intent via cli
1181 """
1182 try:
1183 # If there are no optional arguments
1184 if not ethType and not ethSrc and not ethDst\
1185 and not bandwidth and not lambdaAlloc \
1186 and not ipProto and not ipSrc and not ipDst \
1187 and not tcpSrc and not tcpDst:
1188 cmd = "add-point-intent"
1189
1190 else:
1191 cmd = "add-point-intent"
1192
1193 if ethType:
1194 cmd += " --ethType " + str( ethType )
1195 if ethSrc:
1196 cmd += " --ethSrc " + str( ethSrc )
1197 if ethDst:
1198 cmd += " --ethDst " + str( ethDst )
1199 if bandwidth:
1200 cmd += " --bandwidth " + str( bandwidth )
1201 if lambdaAlloc:
1202 cmd += " --lambda "
1203 if ipProto:
1204 cmd += " --ipProto " + str( ipProto )
1205 if ipSrc:
1206 cmd += " --ipSrc " + str( ipSrc )
1207 if ipDst:
1208 cmd += " --ipDst " + str( ipDst )
1209 if tcpSrc:
1210 cmd += " --tcpSrc " + str( tcpSrc )
1211 if tcpDst:
1212 cmd += " --tcpDst " + str( tcpDst )
1213
1214 # Check whether the user appended the port
1215 # or provided it as an input
1216 if "/" in ingressDevice:
1217 cmd += " " + str( ingressDevice )
1218 else:
1219 if not portIngress:
1220 main.log.error( "You must specify the ingress port" )
1221 # TODO: perhaps more meaningful return
1222 # Would it make sense to throw an exception and exit
1223 # the test?
1224 return None
1225
1226 cmd += " " + \
1227 str( ingressDevice ) + "/" +\
1228 str( portIngress ) + " "
1229
1230 if "/" in egressDevice:
1231 cmd += " " + str( egressDevice )
1232 else:
1233 if not portEgress:
1234 main.log.error( "You must specify the egress port" )
1235 return None
1236
1237 cmd += " " +\
1238 str( egressDevice ) + "/" +\
1239 str( portEgress )
1240
1241 handle = self.sendline( cmd )
1242 assert "Command not found:" not in handle, handle
1243 # If error, return error message
1244 if re.search( "Error", handle ):
1245 main.log.error( "Error in adding point-to-point intent" )
1246 return None
1247 else:
1248 # TODO: print out all the options in this message?
1249 main.log.info( "Point-to-point intent installed between " +
1250 str( ingressDevice ) + " and " +
1251 str( egressDevice ) )
1252 match = re.search('id=0x([\da-f]+),', handle)
1253 if match:
1254 return match.group()[3:-1]
1255 else:
1256 main.log.error( "Error, intent ID not found" )
1257 return None
1258 except AssertionError:
1259 main.log.exception( "" )
1260 return None
1261 except TypeError:
1262 main.log.exception( self.name + ": Object not as expected" )
1263 return None
1264 except pexpect.EOF:
1265 main.log.error( self.name + ": EOF exception found" )
1266 main.log.error( self.name + ": " + self.handle.before )
1267 main.cleanup()
1268 main.exit()
1269 except Exception:
1270 main.log.exception( self.name + ": Uncaught exception!" )
1271 main.cleanup()
1272 main.exit()
1273
1274 def addMultipointToSinglepointIntent(
1275 self,
1276 ingressDeviceList,
1277 egressDevice,
1278 portIngressList=None,
1279 portEgress="",
1280 ethType="",
1281 ethSrc="",
1282 ethDst="",
1283 bandwidth="",
1284 lambdaAlloc=False,
1285 ipProto="",
1286 ipSrc="",
1287 ipDst="",
1288 tcpSrc="",
1289 tcpDst="",
1290 setEthSrc="",
1291 setEthDst="" ):
1292 """
1293 Note:
1294 This function assumes the format of all ingress devices
1295 is same. That is, all ingress devices include port numbers
1296 with a "/" or all ingress devices could specify device
1297 ids and port numbers seperately.
1298 Required:
1299 * ingressDeviceList: List of device ids of ingress device
1300 ( Atleast 2 ingress devices required in the list )
1301 * egressDevice: device id of egress device
1302 Optional:
1303 * ethType: specify ethType
1304 * ethSrc: specify ethSrc ( i.e. src mac addr )
1305 * ethDst: specify ethDst ( i.e. dst mac addr )
1306 * bandwidth: specify bandwidth capacity of link
1307 * lambdaAlloc: if True, intent will allocate lambda
1308 for the specified intent
1309 * ipProto: specify ip protocol
1310 * ipSrc: specify ip source address
1311 * ipDst: specify ip destination address
1312 * tcpSrc: specify tcp source port
1313 * tcpDst: specify tcp destination port
1314 * setEthSrc: action to Rewrite Source MAC Address
1315 * setEthDst: action to Rewrite Destination MAC Address
1316 Description:
1317 Adds a multipoint-to-singlepoint intent ( uni-directional ) by
1318 specifying device id's and optional fields
1319 Returns:
1320 A string of the intent id or None on error
1321
1322 NOTE: This function may change depending on the
1323 options developers provide for multipoint-to-singlepoint
1324 intent via cli
1325 """
1326 try:
1327 # If there are no optional arguments
1328 if not ethType and not ethSrc and not ethDst\
1329 and not bandwidth and not lambdaAlloc\
1330 and not ipProto and not ipSrc and not ipDst\
1331 and not tcpSrc and not tcpDst and not setEthSrc\
1332 and not setEthDst:
1333 cmd = "add-multi-to-single-intent"
1334
1335 else:
1336 cmd = "add-multi-to-single-intent"
1337
1338 if ethType:
1339 cmd += " --ethType " + str( ethType )
1340 if ethSrc:
1341 cmd += " --ethSrc " + str( ethSrc )
1342 if ethDst:
1343 cmd += " --ethDst " + str( ethDst )
1344 if bandwidth:
1345 cmd += " --bandwidth " + str( bandwidth )
1346 if lambdaAlloc:
1347 cmd += " --lambda "
1348 if ipProto:
1349 cmd += " --ipProto " + str( ipProto )
1350 if ipSrc:
1351 cmd += " --ipSrc " + str( ipSrc )
1352 if ipDst:
1353 cmd += " --ipDst " + str( ipDst )
1354 if tcpSrc:
1355 cmd += " --tcpSrc " + str( tcpSrc )
1356 if tcpDst:
1357 cmd += " --tcpDst " + str( tcpDst )
1358 if setEthSrc:
1359 cmd += " --setEthSrc " + str( setEthSrc )
1360 if setEthDst:
1361 cmd += " --setEthDst " + str( setEthDst )
1362
1363 # Check whether the user appended the port
1364 # or provided it as an input
1365
1366 if portIngressList is None:
1367 for ingressDevice in ingressDeviceList:
1368 if "/" in ingressDevice:
1369 cmd += " " + str( ingressDevice )
1370 else:
1371 main.log.error( "You must specify " +
1372 "the ingress port" )
1373 # TODO: perhaps more meaningful return
1374 return main.FALSE
1375 else:
1376 if len( ingressDeviceList ) == len( portIngressList ):
1377 for ingressDevice, portIngress in zip( ingressDeviceList,
1378 portIngressList ):
1379 cmd += " " + \
1380 str( ingressDevice ) + "/" +\
1381 str( portIngress ) + " "
1382 else:
1383 main.log.error( "Device list and port list does not " +
1384 "have the same length" )
1385 return main.FALSE
1386 if "/" in egressDevice:
1387 cmd += " " + str( egressDevice )
1388 else:
1389 if not portEgress:
1390 main.log.error( "You must specify " +
1391 "the egress port" )
1392 return main.FALSE
1393
1394 cmd += " " +\
1395 str( egressDevice ) + "/" +\
1396 str( portEgress )
1397 handle = self.sendline( cmd )
1398 assert "Command not found:" not in handle, handle
1399 # If error, return error message
1400 if re.search( "Error", handle ):
1401 main.log.error( "Error in adding multipoint-to-singlepoint " +
1402 "intent" )
1403 return None
1404 else:
1405 match = re.search('id=0x([\da-f]+),', handle)
1406 if match:
1407 return match.group()[3:-1]
1408 else:
1409 main.log.error( "Error, intent ID not found" )
1410 return None
1411 except AssertionError:
1412 main.log.exception( "" )
1413 return None
1414 except TypeError:
1415 main.log.exception( self.name + ": Object not as expected" )
1416 return None
1417 except pexpect.EOF:
1418 main.log.error( self.name + ": EOF exception found" )
1419 main.log.error( self.name + ": " + self.handle.before )
1420 main.cleanup()
1421 main.exit()
1422 except Exception:
1423 main.log.exception( self.name + ": Uncaught exception!" )
1424 main.cleanup()
1425 main.exit()
1426
1427 def addSinglepointToMultipointIntent(
1428 self,
1429 ingressDevice,
1430 egressDeviceList,
1431 portIngress="",
1432 portEgressList=None,
1433 ethType="",
1434 ethSrc="",
1435 ethDst="",
1436 bandwidth="",
1437 lambdaAlloc=False,
1438 ipProto="",
1439 ipSrc="",
1440 ipDst="",
1441 tcpSrc="",
1442 tcpDst="",
1443 setEthSrc="",
1444 setEthDst="" ):
1445 """
1446 Note:
1447 This function assumes the format of all egress devices
1448 is same. That is, all egress devices include port numbers
1449 with a "/" or all egress devices could specify device
1450 ids and port numbers seperately.
1451 Required:
1452 * EgressDeviceList: List of device ids of egress device
1453 ( Atleast 2 eress devices required in the list )
1454 * ingressDevice: device id of ingress device
1455 Optional:
1456 * ethType: specify ethType
1457 * ethSrc: specify ethSrc ( i.e. src mac addr )
1458 * ethDst: specify ethDst ( i.e. dst mac addr )
1459 * bandwidth: specify bandwidth capacity of link
1460 * lambdaAlloc: if True, intent will allocate lambda
1461 for the specified intent
1462 * ipProto: specify ip protocol
1463 * ipSrc: specify ip source address
1464 * ipDst: specify ip destination address
1465 * tcpSrc: specify tcp source port
1466 * tcpDst: specify tcp destination port
1467 * setEthSrc: action to Rewrite Source MAC Address
1468 * setEthDst: action to Rewrite Destination MAC Address
1469 Description:
1470 Adds a singlepoint-to-multipoint intent ( uni-directional ) by
1471 specifying device id's and optional fields
1472 Returns:
1473 A string of the intent id or None on error
1474
1475 NOTE: This function may change depending on the
1476 options developers provide for singlepoint-to-multipoint
1477 intent via cli
1478 """
1479 try:
1480 # If there are no optional arguments
1481 if not ethType and not ethSrc and not ethDst\
1482 and not bandwidth and not lambdaAlloc\
1483 and not ipProto and not ipSrc and not ipDst\
1484 and not tcpSrc and not tcpDst and not setEthSrc\
1485 and not setEthDst:
1486 cmd = "add-single-to-multi-intent"
1487
1488 else:
1489 cmd = "add-single-to-multi-intent"
1490
1491 if ethType:
1492 cmd += " --ethType " + str( ethType )
1493 if ethSrc:
1494 cmd += " --ethSrc " + str( ethSrc )
1495 if ethDst:
1496 cmd += " --ethDst " + str( ethDst )
1497 if bandwidth:
1498 cmd += " --bandwidth " + str( bandwidth )
1499 if lambdaAlloc:
1500 cmd += " --lambda "
1501 if ipProto:
1502 cmd += " --ipProto " + str( ipProto )
1503 if ipSrc:
1504 cmd += " --ipSrc " + str( ipSrc )
1505 if ipDst:
1506 cmd += " --ipDst " + str( ipDst )
1507 if tcpSrc:
1508 cmd += " --tcpSrc " + str( tcpSrc )
1509 if tcpDst:
1510 cmd += " --tcpDst " + str( tcpDst )
1511 if setEthSrc:
1512 cmd += " --setEthSrc " + str( setEthSrc )
1513 if setEthDst:
1514 cmd += " --setEthDst " + str( setEthDst )
1515
1516 # Check whether the user appended the port
1517 # or provided it as an input
1518
1519 if "/" in ingressDevice:
1520 cmd += " " + str( ingressDevice )
1521 else:
1522 if not portIngress:
1523 main.log.error( "You must specify " +
1524 "the Ingress port" )
1525 return main.FALSE
1526
1527 cmd += " " +\
1528 str( ingressDevice ) + "/" +\
1529 str( portIngress )
1530
1531 if portEgressList is None:
1532 for egressDevice in egressDeviceList:
1533 if "/" in egressDevice:
1534 cmd += " " + str( egressDevice )
1535 else:
1536 main.log.error( "You must specify " +
1537 "the egress port" )
1538 # TODO: perhaps more meaningful return
1539 return main.FALSE
1540 else:
1541 if len( egressDeviceList ) == len( portEgressList ):
1542 for egressDevice, portEgress in zip( egressDeviceList,
1543 portEgressList ):
1544 cmd += " " + \
1545 str( egressDevice ) + "/" +\
1546 str( portEgress )
1547 else:
1548 main.log.error( "Device list and port list does not " +
1549 "have the same length" )
1550 return main.FALSE
1551 handle = self.sendline( cmd )
1552 assert "Command not found:" not in handle, handle
1553 # If error, return error message
1554 if re.search( "Error", handle ):
1555 main.log.error( "Error in adding singlepoint-to-multipoint " +
1556 "intent" )
1557 return None
1558 else:
1559 match = re.search('id=0x([\da-f]+),', handle)
1560 if match:
1561 return match.group()[3:-1]
1562 else:
1563 main.log.error( "Error, intent ID not found" )
1564 return None
1565 except AssertionError:
1566 main.log.exception( "" )
1567 return None
1568 except TypeError:
1569 main.log.exception( self.name + ": Object not as expected" )
1570 return None
1571 except pexpect.EOF:
1572 main.log.error( self.name + ": EOF exception found" )
1573 main.log.error( self.name + ": " + self.handle.before )
1574 main.cleanup()
1575 main.exit()
1576 except Exception:
1577 main.log.exception( self.name + ": Uncaught exception!" )
1578 main.cleanup()
1579 main.exit()
1580
1581 def addMplsIntent(
1582 self,
1583 ingressDevice,
1584 egressDevice,
1585 ingressPort="",
1586 egressPort="",
1587 ethType="",
1588 ethSrc="",
1589 ethDst="",
1590 bandwidth="",
1591 lambdaAlloc=False,
1592 ipProto="",
1593 ipSrc="",
1594 ipDst="",
1595 tcpSrc="",
1596 tcpDst="",
1597 ingressLabel="",
1598 egressLabel="",
1599 priority=""):
1600 """
1601 Required:
1602 * ingressDevice: device id of ingress device
1603 * egressDevice: device id of egress device
1604 Optional:
1605 * ethType: specify ethType
1606 * ethSrc: specify ethSrc ( i.e. src mac addr )
1607 * ethDst: specify ethDst ( i.e. dst mac addr )
1608 * bandwidth: specify bandwidth capacity of link
1609 * lambdaAlloc: if True, intent will allocate lambda
1610 for the specified intent
1611 * ipProto: specify ip protocol
1612 * ipSrc: specify ip source address
1613 * ipDst: specify ip destination address
1614 * tcpSrc: specify tcp source port
1615 * tcpDst: specify tcp destination port
1616 * ingressLabel: Ingress MPLS label
1617 * egressLabel: Egress MPLS label
1618 Description:
1619 Adds MPLS intent by
1620 specifying device id's and optional fields
1621 Returns:
1622 A string of the intent id or None on error
1623
1624 NOTE: This function may change depending on the
1625 options developers provide for MPLS
1626 intent via cli
1627 """
1628 try:
1629 # If there are no optional arguments
1630 if not ethType and not ethSrc and not ethDst\
1631 and not bandwidth and not lambdaAlloc \
1632 and not ipProto and not ipSrc and not ipDst \
1633 and not tcpSrc and not tcpDst and not ingressLabel \
1634 and not egressLabel:
1635 cmd = "add-mpls-intent"
1636
1637 else:
1638 cmd = "add-mpls-intent"
1639
1640 if ethType:
1641 cmd += " --ethType " + str( ethType )
1642 if ethSrc:
1643 cmd += " --ethSrc " + str( ethSrc )
1644 if ethDst:
1645 cmd += " --ethDst " + str( ethDst )
1646 if bandwidth:
1647 cmd += " --bandwidth " + str( bandwidth )
1648 if lambdaAlloc:
1649 cmd += " --lambda "
1650 if ipProto:
1651 cmd += " --ipProto " + str( ipProto )
1652 if ipSrc:
1653 cmd += " --ipSrc " + str( ipSrc )
1654 if ipDst:
1655 cmd += " --ipDst " + str( ipDst )
1656 if tcpSrc:
1657 cmd += " --tcpSrc " + str( tcpSrc )
1658 if tcpDst:
1659 cmd += " --tcpDst " + str( tcpDst )
1660 if ingressLabel:
1661 cmd += " --ingressLabel " + str( ingressLabel )
1662 if egressLabel:
1663 cmd += " --egressLabel " + str( egressLabel )
1664 if priority:
1665 cmd += " --priority " + str( priority )
1666
1667 # Check whether the user appended the port
1668 # or provided it as an input
1669 if "/" in ingressDevice:
1670 cmd += " " + str( ingressDevice )
1671 else:
1672 if not ingressPort:
1673 main.log.error( "You must specify the ingress port" )
1674 return None
1675
1676 cmd += " " + \
1677 str( ingressDevice ) + "/" +\
1678 str( ingressPort ) + " "
1679
1680 if "/" in egressDevice:
1681 cmd += " " + str( egressDevice )
1682 else:
1683 if not egressPort:
1684 main.log.error( "You must specify the egress port" )
1685 return None
1686
1687 cmd += " " +\
1688 str( egressDevice ) + "/" +\
1689 str( egressPort )
1690
1691 handle = self.sendline( cmd )
1692 assert "Command not found:" not in handle, handle
1693 # If error, return error message
1694 if re.search( "Error", handle ):
1695 main.log.error( "Error in adding mpls intent" )
1696 return None
1697 else:
1698 # TODO: print out all the options in this message?
1699 main.log.info( "MPLS intent installed between " +
1700 str( ingressDevice ) + " and " +
1701 str( egressDevice ) )
1702 match = re.search('id=0x([\da-f]+),', handle)
1703 if match:
1704 return match.group()[3:-1]
1705 else:
1706 main.log.error( "Error, intent ID not found" )
1707 return None
1708 except AssertionError:
1709 main.log.exception( "" )
1710 return None
1711 except TypeError:
1712 main.log.exception( self.name + ": Object not as expected" )
1713 return None
1714 except pexpect.EOF:
1715 main.log.error( self.name + ": EOF exception found" )
1716 main.log.error( self.name + ": " + self.handle.before )
1717 main.cleanup()
1718 main.exit()
1719 except Exception:
1720 main.log.exception( self.name + ": Uncaught exception!" )
1721 main.cleanup()
1722 main.exit()
1723
1724 def removeIntent( self, intentId, app='org.onosproject.cli',
1725 purge=False, sync=False ):
1726 """
1727 Remove intent for specified application id and intent id
1728 Optional args:-
1729 -s or --sync: Waits for the removal before returning
1730 -p or --purge: Purge the intent from the store after removal
1731
1732 Returns:
1733 main.False on error and
1734 cli output otherwise
1735 """
1736 try:
1737 cmdStr = "remove-intent"
1738 if purge:
1739 cmdStr += " -p"
1740 if sync:
1741 cmdStr += " -s"
1742
1743 cmdStr += " " + app + " " + str( intentId )
1744 handle = self.sendline( cmdStr )
1745 assert "Command not found:" not in handle, handle
1746 if re.search( "Error", handle ):
1747 main.log.error( "Error in removing intent" )
1748 return main.FALSE
1749 else:
1750 # TODO: Should this be main.TRUE
1751 return handle
1752 except AssertionError:
1753 main.log.exception( "" )
1754 return None
1755 except TypeError:
1756 main.log.exception( self.name + ": Object not as expected" )
1757 return None
1758 except pexpect.EOF:
1759 main.log.error( self.name + ": EOF exception found" )
1760 main.log.error( self.name + ": " + self.handle.before )
1761 main.cleanup()
1762 main.exit()
1763 except Exception:
1764 main.log.exception( self.name + ": Uncaught exception!" )
1765 main.cleanup()
1766 main.exit()
1767
1768 def removeAllIntents( self, purge=False, sync=False, app='org.onosproject.cli' ):
1769 """
1770 Description:
1771 Remove all the intents
1772 Optional args:-
1773 -s or --sync: Waits for the removal before returning
1774 -p or --purge: Purge the intent from the store after removal
1775 Returns:
1776 Returns main.TRUE if all intents are removed, otherwise returns
1777 main.FALSE; Returns None for exception
1778 """
1779 try:
1780 cmdStr = "remove-intent"
1781 if purge:
1782 cmdStr += " -p"
1783 if sync:
1784 cmdStr += " -s"
1785
1786 cmdStr += " " + app
1787 handle = self.sendline( cmdStr )
1788 assert "Command not found:" not in handle, handle
1789 if re.search( "Error", handle ):
1790 main.log.error( "Error in removing intent" )
1791 return main.FALSE
1792 else:
1793 return main.TRUE
1794 except AssertionError:
1795 main.log.exception( "" )
1796 return None
1797 except TypeError:
1798 main.log.exception( self.name + ": Object not as expected" )
1799 return None
1800 except pexpect.EOF:
1801 main.log.error( self.name + ": EOF exception found" )
1802 main.log.error( self.name + ": " + self.handle.before )
1803 main.cleanup()
1804 main.exit()
1805 except Exception:
1806 main.log.exception( self.name + ": Uncaught exception!" )
1807 main.cleanup()
1808 main.exit()
1809
1810 def purgeWithdrawnIntents( self ):
1811 """
1812 Purges all WITHDRAWN Intents
1813 """
1814 try:
1815 cmdStr = "purge-intents"
1816 handle = self.sendline( cmdStr )
1817 assert "Command not found:" not in handle, handle
1818 if re.search( "Error", handle ):
1819 main.log.error( "Error in purging intents" )
1820 return main.FALSE
1821 else:
1822 return main.TRUE
1823 except AssertionError:
1824 main.log.exception( "" )
1825 return None
1826 except TypeError:
1827 main.log.exception( self.name + ": Object not as expected" )
1828 return None
1829 except pexpect.EOF:
1830 main.log.error( self.name + ": EOF exception found" )
1831 main.log.error( self.name + ": " + self.handle.before )
1832 main.cleanup()
1833 main.exit()
1834 except Exception:
1835 main.log.exception( self.name + ": Uncaught exception!" )
1836 main.cleanup()
1837 main.exit()
1838
1839 def routes( self, jsonFormat=False ):
1840 """
1841 NOTE: This method should be used after installing application:
1842 onos-app-sdnip
1843 Optional:
1844 * jsonFormat: enable output formatting in json
1845 Description:
1846 Obtain all routes in the system
1847 """
1848 try:
1849 cmdStr = "routes"
1850 if jsonFormat:
1851 cmdStr += " -j"
1852 handle = self.sendline( cmdStr )
1853 assert "Command not found:" not in handle, handle
1854 return handle
1855 except AssertionError:
1856 main.log.exception( "" )
1857 return None
1858 except TypeError:
1859 main.log.exception( self.name + ": Object not as expected" )
1860 return None
1861 except pexpect.EOF:
1862 main.log.error( self.name + ": EOF exception found" )
1863 main.log.error( self.name + ": " + self.handle.before )
1864 main.cleanup()
1865 main.exit()
1866 except Exception:
1867 main.log.exception( self.name + ": Uncaught exception!" )
1868 main.cleanup()
1869 main.exit()
1870
1871 def ipv4RouteNumber( self ):
1872 """
1873 NOTE: This method should be used after installing application:
1874 onos-app-sdnip
1875 Description:
1876 Obtain the total IPv4 routes number in the system
1877 """
1878 try:
1879 cmdStr = "routes -s -j"
1880 handle = self.sendline( cmdStr )
1881 assert "Command not found:" not in handle, handle
1882 jsonResult = json.loads( handle )
1883 return jsonResult['totalRoutes4']
1884 except AssertionError:
1885 main.log.exception( "" )
1886 return None
1887 except ( TypeError, ValueError ):
1888 main.log.exception( "{}: Object not as expected: {!r}".format( self.name, handle ) )
1889 return None
1890 except pexpect.EOF:
1891 main.log.error( self.name + ": EOF exception found" )
1892 main.log.error( self.name + ": " + self.handle.before )
1893 main.cleanup()
1894 main.exit()
1895 except Exception:
1896 main.log.exception( self.name + ": Uncaught exception!" )
1897 main.cleanup()
1898 main.exit()
1899
1900 def intents( self, jsonFormat = True, summary = False, **intentargs):
1901 """
1902 Description:
1903 Obtain intents from the ONOS cli.
1904 Optional:
1905 * jsonFormat: Enable output formatting in json, default to True
1906 * summary: Whether only output the intent summary, defaults to False
1907 * type: Only output a certain type of intent. This options is valid
1908 only when jsonFormat is True and summary is True.
1909 """
1910 try:
1911 cmdStr = "intents"
1912 if summary:
1913 cmdStr += " -s"
1914 if jsonFormat:
1915 cmdStr += " -j"
1916 handle = self.sendline( cmdStr )
1917 assert "Command not found:" not in handle, handle
1918 args = utilities.parse_args( [ "TYPE" ], **intentargs )
1919 if "TYPE" in args.keys():
1920 intentType = args[ "TYPE" ]
1921 else:
1922 intentType = ""
1923 # IF we want the summary of a specific intent type
1924 if jsonFormat and summary and ( intentType != "" ):
1925 jsonResult = json.loads( handle )
1926 if intentType in jsonResult.keys():
1927 return jsonResult[ intentType ]
1928 else:
1929 main.log.error( "unknown TYPE, returning all types of intents" )
1930 return handle
1931 else:
1932 return handle
1933 except AssertionError:
1934 main.log.exception( "" )
1935 return None
1936 except ( TypeError, ValueError ):
1937 main.log.exception( "{}: Object not as expected: {!r}".format( self.name, handle ) )
1938 return None
1939 except pexpect.EOF:
1940 main.log.error( self.name + ": EOF exception found" )
1941 main.log.error( self.name + ": " + self.handle.before )
1942 main.cleanup()
1943 main.exit()
1944 except Exception:
1945 main.log.exception( self.name + ": Uncaught exception!" )
1946 main.cleanup()
1947 main.exit()
1948
1949 def getIntentState(self, intentsId, intentsJson=None):
1950 """
1951 Check intent state.
1952 Accepts a single intent ID (string type) or a list of intent IDs.
1953 Returns the state(string type) of the id if a single intent ID is
1954 accepted.
1955 Returns a dictionary with intent IDs as the key and its
1956 corresponding states as the values
1957 Parameters:
1958 intentId: intent ID (string type)
1959 intentsJson: parsed json object from the onos:intents api
1960 Returns:
1961 state = An intent's state- INSTALL,WITHDRAWN etc.
1962 stateDict = Dictionary of intent's state. intent ID as the keys and
1963 state as the values.
1964 """
1965 try:
1966 state = "State is Undefined"
1967 if not intentsJson:
1968 rawJson = self.intents()
1969 else:
1970 rawJson = intentsJson
1971 parsedIntentsJson = json.loads( rawJson )
1972 if isinstance( intentsId, types.StringType ):
1973 for intent in parsedIntentsJson:
1974 if intentsId == intent[ 'id' ]:
1975 state = intent[ 'state' ]
1976 return state
1977 main.log.info( "Cannot find intent ID" + str( intentsId ) +
1978 " on the list" )
1979 return state
1980 elif isinstance( intentsId, types.ListType ):
1981 dictList = []
1982 for i in xrange( len( intentsId ) ):
1983 stateDict = {}
1984 for intents in parsedIntentsJson:
1985 if intentsId[ i ] == intents[ 'id' ]:
1986 stateDict[ 'state' ] = intents[ 'state' ]
1987 stateDict[ 'id' ] = intentsId[ i ]
1988 dictList.append( stateDict )
1989 break
1990 if len( intentsId ) != len( dictList ):
1991 main.log.info( "Cannot find some of the intent ID state" )
1992 return dictList
1993 else:
1994 main.log.info( "Invalid intents ID entry" )
1995 return None
1996 except ( TypeError, ValueError ):
1997 main.log.exception( "{}: Object not as expected: {!r}".format( self.name, rawJson ) )
1998 return None
1999 except pexpect.EOF:
2000 main.log.error( self.name + ": EOF exception found" )
2001 main.log.error( self.name + ": " + self.handle.before )
2002 main.cleanup()
2003 main.exit()
2004 except Exception:
2005 main.log.exception( self.name + ": Uncaught exception!" )
2006 main.cleanup()
2007 main.exit()
2008
2009 def checkIntentState( self, intentsId, expectedState='INSTALLED' ):
2010 """
2011 Description:
2012 Check intents state
2013 Required:
2014 intentsId - List of intents ID to be checked
2015 Optional:
2016 expectedState - Check the expected state(s) of each intents
2017 state in the list.
2018 *NOTE: You can pass in a list of expected state,
2019 Eg: expectedState = [ 'INSTALLED' , 'INSTALLING' ]
2020 Return:
2021 Returns main.TRUE only if all intent are the same as expected states
2022 , otherwise, returns main.FALSE.
2023 """
2024 try:
2025 # Generating a dictionary: intent id as a key and state as value
2026 returnValue = main.TRUE
2027 intentsDict = self.getIntentState( intentsId )
2028 if len( intentsId ) != len( intentsDict ):
2029 main.log.info( self.name + ": There is something wrong " +
2030 "getting intents state" )
2031 return main.FALSE
2032
2033 if isinstance( expectedState, types.StringType ):
2034 for intents in intentsDict:
2035 if intents.get( 'state' ) != expectedState:
2036 main.log.debug( self.name + " : Intent ID - " +
2037 intents.get( 'id' ) +
2038 " actual state = " +
2039 intents.get( 'state' )
2040 + " does not equal expected state = "
2041 + expectedState )
2042 returnValue = main.FALSE
2043
2044 elif isinstance( expectedState, types.ListType ):
2045 for intents in intentsDict:
2046 if not any( state == intents.get( 'state' ) for state in
2047 expectedState ):
2048 main.log.debug( self.name + " : Intent ID - " +
2049 intents.get( 'id' ) +
2050 " actual state = " +
2051 intents.get( 'state' ) +
2052 " does not equal expected states = "
2053 + str( expectedState ) )
2054 returnValue = main.FALSE
2055
2056 if returnValue == main.TRUE:
2057 main.log.info( self.name + ": All " +
2058 str( len( intentsDict ) ) +
2059 " intents are in " + str( expectedState ) +
2060 " state" )
2061 return returnValue
2062 except TypeError:
2063 main.log.exception( self.name + ": Object not as expected" )
2064 return None
2065 except pexpect.EOF:
2066 main.log.error( self.name + ": EOF exception found" )
2067 main.log.error( self.name + ": " + self.handle.before )
2068 main.cleanup()
2069 main.exit()
2070 except Exception:
2071 main.log.exception( self.name + ": Uncaught exception!" )
2072 main.cleanup()
2073 main.exit()
2074
2075 def checkIntentSummary( self, timeout=60 ):
2076 """
2077 Description:
2078 Check the number of installed intents.
2079 Optional:
2080 timeout - the timeout for pexcept
2081 Return:
2082 Returns main.TRUE only if the number of all installed intents are the same as total intents number
2083 , otherwise, returns main.FALSE.
2084 """
2085
2086 try:
2087 cmd = "intents -s -j"
2088
2089 # Check response if something wrong
2090 response = self.sendline( cmd, timeout=timeout )
2091 if response == None:
2092 return main.False
2093 response = json.loads( response )
2094
2095 # get total and installed number, see if they are match
2096 allState = response.get( 'all' )
2097 if allState.get('total') == allState.get('installed'):
2098 main.log.info( 'Total Intents: {} Installed Intents: {}'.format( allState.get('total'), allState.get('installed') ) )
2099 return main.TRUE
2100 main.log.info( 'Verified Intents failed Excepte intetnes: {} installed intents: {}'.format( allState.get('total'), allState.get('installed') ) )
2101 return main.FALSE
2102
2103 except ( TypeError, ValueError ):
2104 main.log.exception( "{}: Object not as expected: {!r}".format( self.name, response ) )
2105 return None
2106 except pexpect.EOF:
2107 main.log.error( self.name + ": EOF exception found" )
2108 main.log.error( self.name + ": " + self.handle.before )
2109 main.cleanup()
2110 main.exit()
2111 except Exception:
2112 main.log.exception( self.name + ": Uncaught exception!" )
2113 main.cleanup()
2114 main.exit()
2115
2116 def flows( self, state="", jsonFormat=True, timeout=60 ):
2117 """
2118 Optional:
2119 * jsonFormat: enable output formatting in json
2120 Description:
2121 Obtain flows currently installed
2122 """
2123 try:
2124 cmdStr = "flows"
2125 if jsonFormat:
2126 cmdStr += " -j "
2127 cmdStr += state
2128 handle = self.sendline( cmdStr, timeout=timeout )
2129 assert "Command not found:" not in handle, handle
2130 if re.search( "Error:", handle ):
2131 main.log.error( self.name + ": flows() response: " +
2132 str( handle ) )
2133 return handle
2134 except AssertionError:
2135 main.log.exception( "" )
2136 return None
2137 except TypeError:
2138 main.log.exception( self.name + ": Object not as expected" )
2139 return None
2140 except pexpect.TIMEOUT:
2141 main.log.error( self.name + ": ONOS timeout" )
2142 return None
2143 except pexpect.EOF:
2144 main.log.error( self.name + ": EOF exception found" )
2145 main.log.error( self.name + ": " + self.handle.before )
2146 main.cleanup()
2147 main.exit()
2148 except Exception:
2149 main.log.exception( self.name + ": Uncaught exception!" )
2150 main.cleanup()
2151 main.exit()
2152
2153
2154 def checkFlowsState( self, isPENDING=True, timeout=60 ):
2155 """
2156 Description:
2157 Check the if all the current flows are in ADDED state
2158 We check PENDING_ADD, PENDING_REMOVE, REMOVED, and FAILED flows,
2159 if the count of those states is 0, which means all current flows
2160 are in ADDED state, and return main.TRUE otherwise return main.FALSE
2161 Optional:
2162 * isPENDING: whether the PENDING_ADD is also a correct status
2163 Return:
2164 returnValue - Returns main.TRUE only if all flows are in
2165 ADDED state or PENDING_ADD if the isPENDING
2166 parameter is set true, return main.FALSE otherwise.
2167 """
2168 try:
2169 states = ["PENDING_ADD", "PENDING_REMOVE", "REMOVED", "FAILED"]
2170 checkedStates = []
2171 statesCount = [0, 0, 0, 0]
2172 for s in states:
2173 rawFlows = self.flows( state=s, timeout = timeout )
2174 checkedStates.append( json.loads( rawFlows ) )
2175 for i in range( len( states ) ):
2176 for c in checkedStates[i]:
2177 try:
2178 statesCount[i] += int( c.get( "flowCount" ) )
2179 except TypeError:
2180 main.log.exception( "Json object not as expected" )
2181 main.log.info( states[i] + " flows: " + str( statesCount[i] ) )
2182
2183 # We want to count PENDING_ADD if isPENDING is true
2184 if isPENDING:
2185 if statesCount[1] + statesCount[2] + statesCount[3] > 0:
2186 return main.FALSE
2187 else:
2188 if statesCount[0] + statesCount[1] + statesCount[2] + statesCount[3] > 0:
2189 return main.FALSE
2190 return main.TRUE
2191 except ( TypeError, ValueError ):
2192 main.log.exception( "{}: Object not as expected: {!r}".format( self.name, rawFlows ) )
2193 return None
2194 except pexpect.EOF:
2195 main.log.error( self.name + ": EOF exception found" )
2196 main.log.error( self.name + ": " + self.handle.before )
2197 main.cleanup()
2198 main.exit()
2199 except Exception:
2200 main.log.exception( self.name + ": Uncaught exception!" )
2201 main.cleanup()
2202 main.exit()
2203
2204 def pushTestIntents( self, ingress, egress, batchSize, offset="",
2205 options="", timeout=10, background = False ):
2206 """
2207 Description:
2208 Push a number of intents in a batch format to
2209 a specific point-to-point intent definition
2210 Required:
2211 * ingress: specify source dpid
2212 * egress: specify destination dpid
2213 * batchSize: specify number of intents to push
2214 Optional:
2215 * offset: the keyOffset is where the next batch of intents
2216 will be installed
2217 Returns: If failed to push test intents, it will returen None,
2218 if successful, return true.
2219 Timeout expection will return None,
2220 TypeError will return false
2221 other expections will exit()
2222 """
2223 try:
2224 if background:
2225 back = "&"
2226 else:
2227 back = ""
2228 cmd = "push-test-intents {} {} {} {} {} {}".format( options,
2229 ingress,
2230 egress,
2231 batchSize,
2232 offset,
2233 back )
2234 response = self.sendline( cmd, timeout=timeout )
2235 assert "Command not found:" not in response, response
2236 main.log.info( response )
2237 if response == None:
2238 return None
2239
2240 # TODO: We should handle if there is failure in installation
2241 return main.TRUE
2242
2243 except AssertionError:
2244 main.log.exception( "" )
2245 return None
2246 except pexpect.TIMEOUT:
2247 main.log.error( self.name + ": ONOS timeout" )
2248 return None
2249 except pexpect.EOF:
2250 main.log.error( self.name + ": EOF exception found" )
2251 main.log.error( self.name + ": " + self.handle.before )
2252 main.cleanup()
2253 main.exit()
2254 except TypeError:
2255 main.log.exception( self.name + ": Object not as expected" )
2256 return None
2257 except Exception:
2258 main.log.exception( self.name + ": Uncaught exception!" )
2259 main.cleanup()
2260 main.exit()
2261
2262 def getTotalFlowsNum( self, timeout=60 ):
2263 """
2264 Description:
2265 Get the number of ADDED flows.
2266 Return:
2267 The number of ADDED flows
2268 """
2269
2270 try:
2271 # get total added flows number
2272 cmd = "flows -s|grep ADDED|wc -l"
2273 totalFlows = self.sendline( cmd, timeout=timeout )
2274
2275 if totalFlows == None:
2276 # if timeout, we will get total number of all flows, and subtract other states
2277 states = ["PENDING_ADD", "PENDING_REMOVE", "REMOVED", "FAILED"]
2278 checkedStates = []
2279 totalFlows = 0
2280 statesCount = [0, 0, 0, 0]
2281
2282 # get total flows from summary
2283 response = json.loads( self.sendline( "summary -j", timeout=timeout ) )
2284 totalFlows = int( response.get("flows") )
2285
2286 for s in states:
2287 rawFlows = self.flows( state=s, timeout = timeout )
2288 if rawFlows == None:
2289 # if timeout, return the total flows number from summary command
2290 return totalFlows
2291 checkedStates.append( json.loads( rawFlows ) )
2292
2293 # Calculate ADDED flows number, equal total subtracts others
2294 for i in range( len( states ) ):
2295 for c in checkedStates[i]:
2296 try:
2297 statesCount[i] += int( c.get( "flowCount" ) )
2298 except TypeError:
2299 main.log.exception( "Json object not as expected" )
2300 totalFlows = totalFlows - int( statesCount[i] )
2301 main.log.info( states[i] + " flows: " + str( statesCount[i] ) )
2302
2303 return totalFlows
2304
2305 return totalFlows
2306
2307 except TypeError:
2308 main.log.exception( self.name + ": Object not as expected" )
2309 return None
2310 except pexpect.EOF:
2311 main.log.error( self.name + ": EOF exception found" )
2312 main.log.error( self.name + ": " + self.handle.before )
2313 main.cleanup()
2314 main.exit()
2315 except Exception:
2316 main.log.exception( self.name + ": Uncaught exception!" )
2317 main.cleanup()
2318 main.exit()
2319
2320 def getTotalIntentsNum( self ):
2321 """
2322 Description:
2323 Get the total number of intents, include every states.
2324 Return:
2325 The number of intents
2326 """
2327 try:
2328 cmd = "summary -j"
2329 response = self.sendline( cmd )
2330 if response == None:
2331 return -1
2332 response = json.loads( response )
2333 return int( response.get("intents") )
2334 except TypeError:
2335 main.log.exception( self.name + ": Object not as expected" )
2336 return None
2337 except pexpect.EOF:
2338 main.log.error( self.name + ": EOF exception found" )
2339 main.log.error( self.name + ": " + self.handle.before )
2340 main.cleanup()
2341 main.exit()
2342 except Exception:
2343 main.log.exception( self.name + ": Uncaught exception!" )
2344 main.cleanup()
2345 main.exit()
2346
2347 def intentsEventsMetrics( self, jsonFormat=True ):
2348 """
2349 Description:Returns topology metrics
2350 Optional:
2351 * jsonFormat: enable json formatting of output
2352 """
2353 try:
2354 cmdStr = "intents-events-metrics"
2355 if jsonFormat:
2356 cmdStr += " -j"
2357 handle = self.sendline( cmdStr )
2358 assert "Command not found:" not in handle, handle
2359 return handle
2360 except AssertionError:
2361 main.log.exception( "" )
2362 return None
2363 except TypeError:
2364 main.log.exception( self.name + ": Object not as expected" )
2365 return None
2366 except pexpect.EOF:
2367 main.log.error( self.name + ": EOF exception found" )
2368 main.log.error( self.name + ": " + self.handle.before )
2369 main.cleanup()
2370 main.exit()
2371 except Exception:
2372 main.log.exception( self.name + ": Uncaught exception!" )
2373 main.cleanup()
2374 main.exit()
2375
2376 def topologyEventsMetrics( self, jsonFormat=True ):
2377 """
2378 Description:Returns topology metrics
2379 Optional:
2380 * jsonFormat: enable json formatting of output
2381 """
2382 try:
2383 cmdStr = "topology-events-metrics"
2384 if jsonFormat:
2385 cmdStr += " -j"
2386 handle = self.sendline( cmdStr )
2387 assert "Command not found:" not in handle, handle
2388 if handle:
2389 return handle
2390 elif jsonFormat:
2391 # Return empty json
2392 return '{}'
2393 else:
2394 return handle
2395 except AssertionError:
2396 main.log.exception( "" )
2397 return None
2398 except TypeError:
2399 main.log.exception( self.name + ": Object not as expected" )
2400 return None
2401 except pexpect.EOF:
2402 main.log.error( self.name + ": EOF exception found" )
2403 main.log.error( self.name + ": " + self.handle.before )
2404 main.cleanup()
2405 main.exit()
2406 except Exception:
2407 main.log.exception( self.name + ": Uncaught exception!" )
2408 main.cleanup()
2409 main.exit()
2410
2411 # Wrapper functions ****************
2412 # Wrapper functions use existing driver
2413 # functions and extends their use case.
2414 # For example, we may use the output of
2415 # a normal driver function, and parse it
2416 # using a wrapper function
2417
2418 def getAllIntentsId( self ):
2419 """
2420 Description:
2421 Obtain all intent id's in a list
2422 """
2423 try:
2424 # Obtain output of intents function
2425 intentsStr = self.intents(jsonFormat=False)
2426 intentIdList = []
2427
2428 # Parse the intents output for ID's
2429 intentsList = [ s.strip() for s in intentsStr.splitlines() ]
2430 for intents in intentsList:
2431 match = re.search('id=0x([\da-f]+),', intents)
2432 if match:
2433 tmpId = match.group()[3:-1]
2434 intentIdList.append( tmpId )
2435 return intentIdList
2436
2437 except TypeError:
2438 main.log.exception( self.name + ": Object not as expected" )
2439 return None
2440 except pexpect.EOF:
2441 main.log.error( self.name + ": EOF exception found" )
2442 main.log.error( self.name + ": " + self.handle.before )
2443 main.cleanup()
2444 main.exit()
2445 except Exception:
2446 main.log.exception( self.name + ": Uncaught exception!" )
2447 main.cleanup()
2448 main.exit()
2449
2450 def FlowAddedCount( self, deviceId ):
2451 """
2452 Determine the number of flow rules for the given device id that are
2453 in the added state
2454 """
2455 try:
2456 cmdStr = "flows any " + str( deviceId ) + " | " +\
2457 "grep 'state=ADDED' | wc -l"
2458 handle = self.sendline( cmdStr )
2459 assert "Command not found:" not in handle, handle
2460 return handle
2461 except AssertionError:
2462 main.log.exception( "" )
2463 return None
2464 except pexpect.EOF:
2465 main.log.error( self.name + ": EOF exception found" )
2466 main.log.error( self.name + ": " + self.handle.before )
2467 main.cleanup()
2468 main.exit()
2469 except Exception:
2470 main.log.exception( self.name + ": Uncaught exception!" )
2471 main.cleanup()
2472 main.exit()
2473
2474 def getAllDevicesId( self ):
2475 """
2476 Use 'devices' function to obtain list of all devices
2477 and parse the result to obtain a list of all device
2478 id's. Returns this list. Returns empty list if no
2479 devices exist
2480 List is ordered sequentially
2481
2482 This function may be useful if you are not sure of the
2483 device id, and wish to execute other commands using
2484 the ids. By obtaining the list of device ids on the fly,
2485 you can iterate through the list to get mastership, etc.
2486 """
2487 try:
2488 # Call devices and store result string
2489 devicesStr = self.devices( jsonFormat=False )
2490 idList = []
2491
2492 if not devicesStr:
2493 main.log.info( "There are no devices to get id from" )
2494 return idList
2495
2496 # Split the string into list by comma
2497 deviceList = devicesStr.split( "," )
2498 # Get temporary list of all arguments with string 'id='
2499 tempList = [ dev for dev in deviceList if "id=" in dev ]
2500 # Split list further into arguments before and after string
2501 # 'id='. Get the latter portion ( the actual device id ) and
2502 # append to idList
2503 for arg in tempList:
2504 idList.append( arg.split( "id=" )[ 1 ] )
2505 return idList
2506
2507 except TypeError:
2508 main.log.exception( self.name + ": Object not as expected" )
2509 return None
2510 except pexpect.EOF:
2511 main.log.error( self.name + ": EOF exception found" )
2512 main.log.error( self.name + ": " + self.handle.before )
2513 main.cleanup()
2514 main.exit()
2515 except Exception:
2516 main.log.exception( self.name + ": Uncaught exception!" )
2517 main.cleanup()
2518 main.exit()
2519
2520 def getAllNodesId( self ):
2521 """
2522 Uses 'nodes' function to obtain list of all nodes
2523 and parse the result of nodes to obtain just the
2524 node id's.
2525 Returns:
2526 list of node id's
2527 """
2528 try:
2529 nodesStr = self.nodes( jsonFormat=True )
2530 idList = []
2531 # Sample nodesStr output
2532 # id=local, address=127.0.0.1:9876, state=READY *
2533 if not nodesStr:
2534 main.log.info( "There are no nodes to get id from" )
2535 return idList
2536 nodesJson = json.loads( nodesStr )
2537 idList = [ node.get('id') for node in nodesJson ]
2538 return idList
2539 except ( TypeError, ValueError ):
2540 main.log.exception( "{}: Object not as expected: {!r}".format( self.name, nodesStr ) )
2541 return None
2542 except pexpect.EOF:
2543 main.log.error( self.name + ": EOF exception found" )
2544 main.log.error( self.name + ": " + self.handle.before )
2545 main.cleanup()
2546 main.exit()
2547 except Exception:
2548 main.log.exception( self.name + ": Uncaught exception!" )
2549 main.cleanup()
2550 main.exit()
2551
2552 def getDevice( self, dpid=None ):
2553 """
2554 Return the first device from the devices api whose 'id' contains 'dpid'
2555 Return None if there is no match
2556 """
2557 try:
2558 if dpid is None:
2559 return None
2560 else:
2561 dpid = dpid.replace( ':', '' )
2562 rawDevices = self.devices()
2563 devicesJson = json.loads( rawDevices )
2564 # search json for the device with dpid then return the device
2565 for device in devicesJson:
2566 # print "%s in %s?" % ( dpid, device[ 'id' ] )
2567 if dpid in device[ 'id' ]:
2568 return device
2569 return None
2570 except ( TypeError, ValueError ):
2571 main.log.exception( "{}: Object not as expected: {!r}".format( self.name, rawDevices ) )
2572 return None
2573 except pexpect.EOF:
2574 main.log.error( self.name + ": EOF exception found" )
2575 main.log.error( self.name + ": " + self.handle.before )
2576 main.cleanup()
2577 main.exit()
2578 except Exception:
2579 main.log.exception( self.name + ": Uncaught exception!" )
2580 main.cleanup()
2581 main.exit()
2582
2583 def checkStatus( self, ip, numoswitch, numolink, logLevel="info" ):
2584 """
2585 Checks the number of switches & links that ONOS sees against the
2586 supplied values. By default this will report to main.log, but the
2587 log level can be specified.
2588
2589 Params: ip = ip used for the onos cli
2590 numoswitch = expected number of switches
2591 numolink = expected number of links
2592 logLevel = level to log to. Currently accepts
2593 'info', 'warn' and 'report'
2594
2595
2596 logLevel can
2597
2598 Returns: main.TRUE if the number of switches and links are correct,
2599 main.FALSE if the number of switches and links is incorrect,
2600 and main.ERROR otherwise
2601 """
2602 try:
2603 topology = self.getTopology( ip )
2604 if topology == {}:
2605 return main.ERROR
2606 output = ""
2607 # Is the number of switches is what we expected
2608 devices = topology.get( 'devices', False )
2609 links = topology.get( 'links', False )
2610 if devices is False or links is False:
2611 return main.ERROR
2612 switchCheck = ( int( devices ) == int( numoswitch ) )
2613 # Is the number of links is what we expected
2614 linkCheck = ( int( links ) == int( numolink ) )
2615 if ( switchCheck and linkCheck ):
2616 # We expected the correct numbers
2617 output += "The number of links and switches match " +\
2618 "what was expected"
2619 result = main.TRUE
2620 else:
2621 output += "The number of links and switches does not match " +\
2622 "what was expected"
2623 result = main.FALSE
2624 output = output + "\n ONOS sees %i devices (%i expected) \
2625 and %i links (%i expected)" % (
2626 int( devices ), int( numoswitch ), int( links ),
2627 int( numolink ) )
2628 if logLevel == "report":
2629 main.log.report( output )
2630 elif logLevel == "warn":
2631 main.log.warn( output )
2632 else:
2633 main.log.info( self.name + ": " + output )
2634 return result
2635 except TypeError:
2636 main.log.exception( self.name + ": Object not as expected" )
2637 return None
2638 except pexpect.EOF:
2639 main.log.error( self.name + ": EOF exception found" )
2640 main.log.error( self.name + ": " + self.handle.before )
2641 main.cleanup()
2642 main.exit()
2643 except Exception:
2644 main.log.exception( self.name + ": Uncaught exception!" )
2645 main.cleanup()
2646 main.exit()
2647
2648 def deviceRole( self, deviceId, onosNode, role="master" ):
2649 """
2650 Calls the device-role cli command.
2651 deviceId must be the id of a device as seen in the onos devices command
2652 onosNode is the ip of one of the onos nodes in the cluster
2653 role must be either master, standby, or none
2654
2655 Returns:
2656 main.TRUE or main.FALSE based on argument verification and
2657 main.ERROR if command returns and error
2658 """
2659 try:
2660 if role.lower() == "master" or role.lower() == "standby" or\
2661 role.lower() == "none":
2662 cmdStr = "device-role " +\
2663 str( deviceId ) + " " +\
2664 str( onosNode ) + " " +\
2665 str( role )
2666 handle = self.sendline( cmdStr )
2667 assert "Command not found:" not in handle, handle
2668 if re.search( "Error", handle ):
2669 # end color output to escape any colours
2670 # from the cli
2671 main.log.error( self.name + ": " +
2672 handle + '\033[0m' )
2673 return main.ERROR
2674 return main.TRUE
2675 else:
2676 main.log.error( "Invalid 'role' given to device_role(). " +
2677 "Value was '" + str(role) + "'." )
2678 return main.FALSE
2679 except AssertionError:
2680 main.log.exception( "" )
2681 return None
2682 except TypeError:
2683 main.log.exception( self.name + ": Object not as expected" )
2684 return None
2685 except pexpect.EOF:
2686 main.log.error( self.name + ": EOF exception found" )
2687 main.log.error( self.name + ": " + self.handle.before )
2688 main.cleanup()
2689 main.exit()
2690 except Exception:
2691 main.log.exception( self.name + ": Uncaught exception!" )
2692 main.cleanup()
2693 main.exit()
2694
2695 def clusters( self, jsonFormat=True ):
2696 """
2697 Lists all clusters
2698 Optional argument:
2699 * jsonFormat - boolean indicating if you want output in json
2700 """
2701 try:
2702 cmdStr = "clusters"
2703 if jsonFormat:
2704 cmdStr += " -j"
2705 handle = self.sendline( cmdStr )
2706 assert "Command not found:" not in handle, handle
2707 return handle
2708 except AssertionError:
2709 main.log.exception( "" )
2710 return None
2711 except TypeError:
2712 main.log.exception( self.name + ": Object not as expected" )
2713 return None
2714 except pexpect.EOF:
2715 main.log.error( self.name + ": EOF exception found" )
2716 main.log.error( self.name + ": " + self.handle.before )
2717 main.cleanup()
2718 main.exit()
2719 except Exception:
2720 main.log.exception( self.name + ": Uncaught exception!" )
2721 main.cleanup()
2722 main.exit()
2723
2724 def electionTestLeader( self ):
2725 """
2726 CLI command to get the current leader for the Election test application
2727 NOTE: Requires installation of the onos-app-election feature
2728 Returns: Node IP of the leader if one exists
2729 None if none exists
2730 Main.FALSE on error
2731 """
2732 try:
2733 cmdStr = "election-test-leader"
2734 response = self.sendline( cmdStr )
2735 assert "Command not found:" not in response, response
2736 # Leader
2737 leaderPattern = "The\scurrent\sleader\sfor\sthe\sElection\s" +\
2738 "app\sis\s(?P<node>.+)\."
2739 nodeSearch = re.search( leaderPattern, response )
2740 if nodeSearch:
2741 node = nodeSearch.group( 'node' )
2742 main.log.info( "Election-test-leader on " + str( self.name ) +
2743 " found " + node + " as the leader" )
2744 return node
2745 # no leader
2746 nullPattern = "There\sis\scurrently\sno\sleader\selected\sfor\s" +\
2747 "the\sElection\sapp"
2748 nullSearch = re.search( nullPattern, response )
2749 if nullSearch:
2750 main.log.info( "Election-test-leader found no leader on " +
2751 self.name )
2752 return None
2753 # error
2754 errorPattern = "Command\snot\sfound"
2755 if re.search( errorPattern, response ):
2756 main.log.error( "Election app is not loaded on " + self.name )
2757 # TODO: Should this be main.ERROR?
2758 return main.FALSE
2759 else:
2760 main.log.error( "Error in electionTestLeader on " + self.name +
2761 ": " + "unexpected response" )
2762 main.log.error( repr( response ) )
2763 return main.FALSE
2764 except AssertionError:
2765 main.log.exception( "" )
2766 return None
2767 except TypeError:
2768 main.log.exception( self.name + ": Object not as expected" )
2769 return main.FALSE
2770 except pexpect.EOF:
2771 main.log.error( self.name + ": EOF exception found" )
2772 main.log.error( self.name + ": " + self.handle.before )
2773 main.cleanup()
2774 main.exit()
2775 except Exception:
2776 main.log.exception( self.name + ": Uncaught exception!" )
2777 main.cleanup()
2778 main.exit()
2779
2780 def electionTestRun( self ):
2781 """
2782 CLI command to run for leadership of the Election test application.
2783 NOTE: Requires installation of the onos-app-election feature
2784 Returns: Main.TRUE on success
2785 Main.FALSE on error
2786 """
2787 try:
2788 cmdStr = "election-test-run"
2789 response = self.sendline( cmdStr )
2790 assert "Command not found:" not in response, response
2791 # success
2792 successPattern = "Entering\sleadership\selections\sfor\sthe\s" +\
2793 "Election\sapp."
2794 search = re.search( successPattern, response )
2795 if search:
2796 main.log.info( self.name + " entering leadership elections " +
2797 "for the Election app." )
2798 return main.TRUE
2799 # error
2800 errorPattern = "Command\snot\sfound"
2801 if re.search( errorPattern, response ):
2802 main.log.error( "Election app is not loaded on " + self.name )
2803 return main.FALSE
2804 else:
2805 main.log.error( "Error in electionTestRun on " + self.name +
2806 ": " + "unexpected response" )
2807 main.log.error( repr( response ) )
2808 return main.FALSE
2809 except AssertionError:
2810 main.log.exception( "" )
2811 return None
2812 except TypeError:
2813 main.log.exception( self.name + ": Object not as expected" )
2814 return main.FALSE
2815 except pexpect.EOF:
2816 main.log.error( self.name + ": EOF exception found" )
2817 main.log.error( self.name + ": " + self.handle.before )
2818 main.cleanup()
2819 main.exit()
2820 except Exception:
2821 main.log.exception( self.name + ": Uncaught exception!" )
2822 main.cleanup()
2823 main.exit()
2824
2825 def electionTestWithdraw( self ):
2826 """
2827 * CLI command to withdraw the local node from leadership election for
2828 * the Election test application.
2829 #NOTE: Requires installation of the onos-app-election feature
2830 Returns: Main.TRUE on success
2831 Main.FALSE on error
2832 """
2833 try:
2834 cmdStr = "election-test-withdraw"
2835 response = self.sendline( cmdStr )
2836 assert "Command not found:" not in response, response
2837 # success
2838 successPattern = "Withdrawing\sfrom\sleadership\selections\sfor" +\
2839 "\sthe\sElection\sapp."
2840 if re.search( successPattern, response ):
2841 main.log.info( self.name + " withdrawing from leadership " +
2842 "elections for the Election app." )
2843 return main.TRUE
2844 # error
2845 errorPattern = "Command\snot\sfound"
2846 if re.search( errorPattern, response ):
2847 main.log.error( "Election app is not loaded on " + self.name )
2848 return main.FALSE
2849 else:
2850 main.log.error( "Error in electionTestWithdraw on " +
2851 self.name + ": " + "unexpected response" )
2852 main.log.error( repr( response ) )
2853 return main.FALSE
2854 except AssertionError:
2855 main.log.exception( "" )
2856 return None
2857 except TypeError:
2858 main.log.exception( self.name + ": Object not as expected" )
2859 return main.FALSE
2860 except pexpect.EOF:
2861 main.log.error( self.name + ": EOF exception found" )
2862 main.log.error( self.name + ": " + self.handle.before )
2863 main.cleanup()
2864 main.exit()
2865 except Exception:
2866 main.log.exception( self.name + ": Uncaught exception!" )
2867 main.cleanup()
2868 main.exit()
2869
2870 def getDevicePortsEnabledCount( self, dpid ):
2871 """
2872 Get the count of all enabled ports on a particular device/switch
2873 """
2874 try:
2875 dpid = str( dpid )
2876 cmdStr = "onos:ports -e " + dpid + " | wc -l"
2877 output = self.sendline( cmdStr )
2878 assert "Command not found:" not in output, output
2879 if re.search( "No such device", output ):
2880 main.log.error( "Error in getting ports" )
2881 return ( output, "Error" )
2882 else:
2883 return output
2884 except AssertionError:
2885 main.log.exception( "" )
2886 return None
2887 except TypeError:
2888 main.log.exception( self.name + ": Object not as expected" )
2889 return ( output, "Error" )
2890 except pexpect.EOF:
2891 main.log.error( self.name + ": EOF exception found" )
2892 main.log.error( self.name + ": " + self.handle.before )
2893 main.cleanup()
2894 main.exit()
2895 except Exception:
2896 main.log.exception( self.name + ": Uncaught exception!" )
2897 main.cleanup()
2898 main.exit()
2899
2900 def getDeviceLinksActiveCount( self, dpid ):
2901 """
2902 Get the count of all enabled ports on a particular device/switch
2903 """
2904 try:
2905 dpid = str( dpid )
2906 cmdStr = "onos:links " + dpid + " | grep ACTIVE | wc -l"
2907 output = self.sendline( cmdStr )
2908 assert "Command not found:" not in output, output
2909 if re.search( "No such device", output ):
2910 main.log.error( "Error in getting ports " )
2911 return ( output, "Error " )
2912 else:
2913 return output
2914 except AssertionError:
2915 main.log.exception( "" )
2916 return None
2917 except TypeError:
2918 main.log.exception( self.name + ": Object not as expected" )
2919 return ( output, "Error " )
2920 except pexpect.EOF:
2921 main.log.error( self.name + ": EOF exception found" )
2922 main.log.error( self.name + ": " + self.handle.before )
2923 main.cleanup()
2924 main.exit()
2925 except Exception:
2926 main.log.exception( self.name + ": Uncaught exception!" )
2927 main.cleanup()
2928 main.exit()
2929
2930 def getAllIntentIds( self ):
2931 """
2932 Return a list of all Intent IDs
2933 """
2934 try:
2935 cmdStr = "onos:intents | grep id="
2936 output = self.sendline( cmdStr )
2937 assert "Command not found:" not in output, output
2938 if re.search( "Error", output ):
2939 main.log.error( "Error in getting ports" )
2940 return ( output, "Error" )
2941 else:
2942 return output
2943 except AssertionError:
2944 main.log.exception( "" )
2945 return None
2946 except TypeError:
2947 main.log.exception( self.name + ": Object not as expected" )
2948 return ( output, "Error" )
2949 except pexpect.EOF:
2950 main.log.error( self.name + ": EOF exception found" )
2951 main.log.error( self.name + ": " + self.handle.before )
2952 main.cleanup()
2953 main.exit()
2954 except Exception:
2955 main.log.exception( self.name + ": Uncaught exception!" )
2956 main.cleanup()
2957 main.exit()
2958
2959 def intentSummary( self ):
2960 """
2961 Returns a dictionary containing the current intent states and the count
2962 """
2963 try:
2964 intents = self.intents( )
2965 states = []
2966 for intent in json.loads( intents ):
2967 states.append( intent.get( 'state', None ) )
2968 out = [ ( i, states.count( i ) ) for i in set( states ) ]
2969 main.log.info( dict( out ) )
2970 return dict( out )
2971 except ( TypeError, ValueError ):
2972 main.log.exception( "{}: Object not as expected: {!r}".format( self.name, intents ) )
2973 return None
2974 except pexpect.EOF:
2975 main.log.error( self.name + ": EOF exception found" )
2976 main.log.error( self.name + ": " + self.handle.before )
2977 main.cleanup()
2978 main.exit()
2979 except Exception:
2980 main.log.exception( self.name + ": Uncaught exception!" )
2981 main.cleanup()
2982 main.exit()
2983
2984 def leaders( self, jsonFormat=True ):
2985 """
2986 Returns the output of the leaders command.
2987 Optional argument:
2988 * jsonFormat - boolean indicating if you want output in json
2989 """
2990 try:
2991 cmdStr = "onos:leaders"
2992 if jsonFormat:
2993 cmdStr += " -j"
2994 output = self.sendline( cmdStr )
2995 assert "Command not found:" not in output, output
2996 return output
2997 except AssertionError:
2998 main.log.exception( "" )
2999 return None
3000 except TypeError:
3001 main.log.exception( self.name + ": Object not as expected" )
3002 return None
3003 except pexpect.EOF:
3004 main.log.error( self.name + ": EOF exception found" )
3005 main.log.error( self.name + ": " + self.handle.before )
3006 main.cleanup()
3007 main.exit()
3008 except Exception:
3009 main.log.exception( self.name + ": Uncaught exception!" )
3010 main.cleanup()
3011 main.exit()
3012
3013 def leaderCandidates( self, jsonFormat=True ):
3014 """
3015 Returns the output of the leaders -c command.
3016 Optional argument:
3017 * jsonFormat - boolean indicating if you want output in json
3018 """
3019 try:
3020 cmdStr = "onos:leaders -c"
3021 if jsonFormat:
3022 cmdStr += " -j"
3023 output = self.sendline( cmdStr )
3024 assert "Command not found:" not in output, output
3025 return output
3026 except AssertionError:
3027 main.log.exception( "" )
3028 return None
3029 except TypeError:
3030 main.log.exception( self.name + ": Object not as expected" )
3031 return None
3032 except pexpect.EOF:
3033 main.log.error( self.name + ": EOF exception found" )
3034 main.log.error( self.name + ": " + self.handle.before )
3035 main.cleanup()
3036 main.exit()
3037 except Exception:
3038 main.log.exception( self.name + ": Uncaught exception!" )
3039 main.cleanup()
3040 main.exit()
3041
3042 def specificLeaderCandidate( self, topic ):
3043 """
3044 Returns a list in format [leader,candidate1,candidate2,...] for a given
3045 topic parameter and an empty list if the topic doesn't exist
3046 If no leader is elected leader in the returned list will be "none"
3047 Returns None if there is a type error processing the json object
3048 """
3049 try:
3050 cmdStr = "onos:leaders -j"
3051 rawOutput = self.sendline( cmdStr )
3052 assert "Command not found:" not in rawOutput, rawOutput
3053 output = json.loads( rawOutput )
3054 results = []
3055 for dict in output:
3056 if dict["topic"] == topic:
3057 leader = dict["leader"]
3058 candidates = re.split( ", ", dict["candidates"][1:-1] )
3059 results.append( leader )
3060 results.extend( candidates )
3061 return results
3062 except AssertionError:
3063 main.log.exception( "" )
3064 return None
3065 except ( TypeError, ValueError ):
3066 main.log.exception( "{}: Object not as expected: {!r}".format( self.name, rawOutput ) )
3067 return None
3068 except pexpect.EOF:
3069 main.log.error( self.name + ": EOF exception found" )
3070 main.log.error( self.name + ": " + self.handle.before )
3071 main.cleanup()
3072 main.exit()
3073 except Exception:
3074 main.log.exception( self.name + ": Uncaught exception!" )
3075 main.cleanup()
3076 main.exit()
3077
3078 def pendingMap( self, jsonFormat=True ):
3079 """
3080 Returns the output of the intent Pending map.
3081 """
3082 try:
3083 cmdStr = "onos:intents -p"
3084 if jsonFormat:
3085 cmdStr += " -j"
3086 output = self.sendline( cmdStr )
3087 assert "Command not found:" not in output, output
3088 return output
3089 except AssertionError:
3090 main.log.exception( "" )
3091 return None
3092 except TypeError:
3093 main.log.exception( self.name + ": Object not as expected" )
3094 return None
3095 except pexpect.EOF:
3096 main.log.error( self.name + ": EOF exception found" )
3097 main.log.error( self.name + ": " + self.handle.before )
3098 main.cleanup()
3099 main.exit()
3100 except Exception:
3101 main.log.exception( self.name + ": Uncaught exception!" )
3102 main.cleanup()
3103 main.exit()
3104
3105 def partitions( self, jsonFormat=True ):
3106 """
3107 Returns the output of the raft partitions command for ONOS.
3108 """
3109 # Sample JSON
3110 # {
3111 # "leader": "tcp://10.128.30.11:7238",
3112 # "members": [
3113 # "tcp://10.128.30.11:7238",
3114 # "tcp://10.128.30.17:7238",
3115 # "tcp://10.128.30.13:7238",
3116 # ],
3117 # "name": "p1",
3118 # "term": 3
3119 # },
3120 try:
3121 cmdStr = "onos:partitions"
3122 if jsonFormat:
3123 cmdStr += " -j"
3124 output = self.sendline( cmdStr )
3125 assert "Command not found:" not in output, output
3126 return output
3127 except AssertionError:
3128 main.log.exception( "" )
3129 return None
3130 except TypeError:
3131 main.log.exception( self.name + ": Object not as expected" )
3132 return None
3133 except pexpect.EOF:
3134 main.log.error( self.name + ": EOF exception found" )
3135 main.log.error( self.name + ": " + self.handle.before )
3136 main.cleanup()
3137 main.exit()
3138 except Exception:
3139 main.log.exception( self.name + ": Uncaught exception!" )
3140 main.cleanup()
3141 main.exit()
3142
3143 def apps( self, jsonFormat=True ):
3144 """
3145 Returns the output of the apps command for ONOS. This command lists
3146 information about installed ONOS applications
3147 """
3148 # Sample JSON object
3149 # [{"name":"org.onosproject.openflow","id":0,"version":"1.2.0",
3150 # "description":"ONOS OpenFlow protocol southbound providers",
3151 # "origin":"ON.Lab","permissions":"[]","featuresRepo":"",
3152 # "features":"[onos-openflow]","state":"ACTIVE"}]
3153 try:
3154 cmdStr = "onos:apps"
3155 if jsonFormat:
3156 cmdStr += " -j"
3157 output = self.sendline( cmdStr )
3158 assert "Command not found:" not in output, output
3159 assert "Error executing command" not in output, output
3160 return output
3161 # FIXME: look at specific exceptions/Errors
3162 except AssertionError:
3163 main.log.exception( "Error in processing onos:app command." )
3164 return None
3165 except TypeError:
3166 main.log.exception( self.name + ": Object not as expected" )
3167 return None
3168 except pexpect.EOF:
3169 main.log.error( self.name + ": EOF exception found" )
3170 main.log.error( self.name + ": " + self.handle.before )
3171 main.cleanup()
3172 main.exit()
3173 except Exception:
3174 main.log.exception( self.name + ": Uncaught exception!" )
3175 main.cleanup()
3176 main.exit()
3177
3178 def appStatus( self, appName ):
3179 """
3180 Uses the onos:apps cli command to return the status of an application.
3181 Returns:
3182 "ACTIVE" - If app is installed and activated
3183 "INSTALLED" - If app is installed and deactivated
3184 "UNINSTALLED" - If app is not installed
3185 None - on error
3186 """
3187 try:
3188 if not isinstance( appName, types.StringType ):
3189 main.log.error( self.name + ".appStatus(): appName must be" +
3190 " a string" )
3191 return None
3192 output = self.apps( jsonFormat=True )
3193 appsJson = json.loads( output )
3194 state = None
3195 for app in appsJson:
3196 if appName == app.get('name'):
3197 state = app.get('state')
3198 break
3199 if state == "ACTIVE" or state == "INSTALLED":
3200 return state
3201 elif state is None:
3202 return "UNINSTALLED"
3203 elif state:
3204 main.log.error( "Unexpected state from 'onos:apps': " +
3205 str( state ) )
3206 return state
3207 except ( TypeError, ValueError ):
3208 main.log.exception( "{}: Object not as expected: {!r}".format( self.name, output ) )
3209 main.stop()
3210 return None
3211 except pexpect.EOF:
3212 main.log.error( self.name + ": EOF exception found" )
3213 main.log.error( self.name + ": " + self.handle.before )
3214 main.cleanup()
3215 main.exit()
3216 except Exception:
3217 main.log.exception( self.name + ": Uncaught exception!" )
3218 main.cleanup()
3219 main.exit()
3220
3221 def app( self, appName, option ):
3222 """
3223 Interacts with the app command for ONOS. This command manages
3224 application inventory.
3225 """
3226 try:
3227 # Validate argument types
3228 valid = True
3229 if not isinstance( appName, types.StringType ):
3230 main.log.error( self.name + ".app(): appName must be a " +
3231 "string" )
3232 valid = False
3233 if not isinstance( option, types.StringType ):
3234 main.log.error( self.name + ".app(): option must be a string" )
3235 valid = False
3236 if not valid:
3237 return main.FALSE
3238 # Validate Option
3239 option = option.lower()
3240 # NOTE: Install may become a valid option
3241 if option == "activate":
3242 pass
3243 elif option == "deactivate":
3244 pass
3245 elif option == "uninstall":
3246 pass
3247 else:
3248 # Invalid option
3249 main.log.error( "The ONOS app command argument only takes " +
3250 "the values: (activate|deactivate|uninstall)" +
3251 "; was given '" + option + "'")
3252 return main.FALSE
3253 cmdStr = "onos:app " + option + " " + appName
3254 output = self.sendline( cmdStr )
3255 if "Error executing command" in output:
3256 main.log.error( "Error in processing onos:app command: " +
3257 str( output ) )
3258 return main.FALSE
3259 elif "No such application" in output:
3260 main.log.error( "The application '" + appName +
3261 "' is not installed in ONOS" )
3262 return main.FALSE
3263 elif "Command not found:" in output:
3264 main.log.error( "Error in processing onos:app command: " +
3265 str( output ) )
3266 return main.FALSE
3267 elif "Unsupported command:" in output:
3268 main.log.error( "Incorrect command given to 'app': " +
3269 str( output ) )
3270 # NOTE: we may need to add more checks here
3271 # else: Command was successful
3272 # main.log.debug( "app response: " + repr( output ) )
3273 return main.TRUE
3274 except TypeError:
3275 main.log.exception( self.name + ": Object not as expected" )
3276 return main.ERROR
3277 except pexpect.EOF:
3278 main.log.error( self.name + ": EOF exception found" )
3279 main.log.error( self.name + ": " + self.handle.before )
3280 main.cleanup()
3281 main.exit()
3282 except Exception:
3283 main.log.exception( self.name + ": Uncaught exception!" )
3284 main.cleanup()
3285 main.exit()
3286
3287 def activateApp( self, appName, check=True ):
3288 """
3289 Activate an app that is already installed in ONOS
3290 appName is the hierarchical app name, not the feature name
3291 If check is True, method will check the status of the app after the
3292 command is issued
3293 Returns main.TRUE if the command was successfully sent
3294 main.FALSE if the cli responded with an error or given
3295 incorrect input
3296 """
3297 try:
3298 if not isinstance( appName, types.StringType ):
3299 main.log.error( self.name + ".activateApp(): appName must be" +
3300 " a string" )
3301 return main.FALSE
3302 status = self.appStatus( appName )
3303 if status == "INSTALLED":
3304 response = self.app( appName, "activate" )
3305 if check and response == main.TRUE:
3306 for i in range(10): # try 10 times then give up
3307 status = self.appStatus( appName )
3308 if status == "ACTIVE":
3309 return main.TRUE
3310 else:
3311 main.log.debug( "The state of application " +
3312 appName + " is " + status )
3313 time.sleep( 1 )
3314 return main.FALSE
3315 else: # not 'check' or command didn't succeed
3316 return response
3317 elif status == "ACTIVE":
3318 return main.TRUE
3319 elif status == "UNINSTALLED":
3320 main.log.error( self.name + ": Tried to activate the " +
3321 "application '" + appName + "' which is not " +
3322 "installed." )
3323 else:
3324 main.log.error( "Unexpected return value from appStatus: " +
3325 str( status ) )
3326 return main.ERROR
3327 except TypeError:
3328 main.log.exception( self.name + ": Object not as expected" )
3329 return main.ERROR
3330 except pexpect.EOF:
3331 main.log.error( self.name + ": EOF exception found" )
3332 main.log.error( self.name + ": " + self.handle.before )
3333 main.cleanup()
3334 main.exit()
3335 except Exception:
3336 main.log.exception( self.name + ": Uncaught exception!" )
3337 main.cleanup()
3338 main.exit()
3339
3340 def deactivateApp( self, appName, check=True ):
3341 """
3342 Deactivate an app that is already activated in ONOS
3343 appName is the hierarchical app name, not the feature name
3344 If check is True, method will check the status of the app after the
3345 command is issued
3346 Returns main.TRUE if the command was successfully sent
3347 main.FALSE if the cli responded with an error or given
3348 incorrect input
3349 """
3350 try:
3351 if not isinstance( appName, types.StringType ):
3352 main.log.error( self.name + ".deactivateApp(): appName must " +
3353 "be a string" )
3354 return main.FALSE
3355 status = self.appStatus( appName )
3356 if status == "INSTALLED":
3357 return main.TRUE
3358 elif status == "ACTIVE":
3359 response = self.app( appName, "deactivate" )
3360 if check and response == main.TRUE:
3361 for i in range(10): # try 10 times then give up
3362 status = self.appStatus( appName )
3363 if status == "INSTALLED":
3364 return main.TRUE
3365 else:
3366 time.sleep( 1 )
3367 return main.FALSE
3368 else: # not check or command didn't succeed
3369 return response
3370 elif status == "UNINSTALLED":
3371 main.log.warn( self.name + ": Tried to deactivate the " +
3372 "application '" + appName + "' which is not " +
3373 "installed." )
3374 return main.TRUE
3375 else:
3376 main.log.error( "Unexpected return value from appStatus: " +
3377 str( status ) )
3378 return main.ERROR
3379 except TypeError:
3380 main.log.exception( self.name + ": Object not as expected" )
3381 return main.ERROR
3382 except pexpect.EOF:
3383 main.log.error( self.name + ": EOF exception found" )
3384 main.log.error( self.name + ": " + self.handle.before )
3385 main.cleanup()
3386 main.exit()
3387 except Exception:
3388 main.log.exception( self.name + ": Uncaught exception!" )
3389 main.cleanup()
3390 main.exit()
3391
3392 def uninstallApp( self, appName, check=True ):
3393 """
3394 Uninstall an app that is already installed in ONOS
3395 appName is the hierarchical app name, not the feature name
3396 If check is True, method will check the status of the app after the
3397 command is issued
3398 Returns main.TRUE if the command was successfully sent
3399 main.FALSE if the cli responded with an error or given
3400 incorrect input
3401 """
3402 # TODO: check with Thomas about the state machine for apps
3403 try:
3404 if not isinstance( appName, types.StringType ):
3405 main.log.error( self.name + ".uninstallApp(): appName must " +
3406 "be a string" )
3407 return main.FALSE
3408 status = self.appStatus( appName )
3409 if status == "INSTALLED":
3410 response = self.app( appName, "uninstall" )
3411 if check and response == main.TRUE:
3412 for i in range(10): # try 10 times then give up
3413 status = self.appStatus( appName )
3414 if status == "UNINSTALLED":
3415 return main.TRUE
3416 else:
3417 time.sleep( 1 )
3418 return main.FALSE
3419 else: # not check or command didn't succeed
3420 return response
3421 elif status == "ACTIVE":
3422 main.log.warn( self.name + ": Tried to uninstall the " +
3423 "application '" + appName + "' which is " +
3424 "currently active." )
3425 response = self.app( appName, "uninstall" )
3426 if check and response == main.TRUE:
3427 for i in range(10): # try 10 times then give up
3428 status = self.appStatus( appName )
3429 if status == "UNINSTALLED":
3430 return main.TRUE
3431 else:
3432 time.sleep( 1 )
3433 return main.FALSE
3434 else: # not check or command didn't succeed
3435 return response
3436 elif status == "UNINSTALLED":
3437 return main.TRUE
3438 else:
3439 main.log.error( "Unexpected return value from appStatus: " +
3440 str( status ) )
3441 return main.ERROR
3442 except TypeError:
3443 main.log.exception( self.name + ": Object not as expected" )
3444 return main.ERROR
3445 except pexpect.EOF:
3446 main.log.error( self.name + ": EOF exception found" )
3447 main.log.error( self.name + ": " + self.handle.before )
3448 main.cleanup()
3449 main.exit()
3450 except Exception:
3451 main.log.exception( self.name + ": Uncaught exception!" )
3452 main.cleanup()
3453 main.exit()
3454
3455 def appIDs( self, jsonFormat=True ):
3456 """
3457 Show the mappings between app id and app names given by the 'app-ids'
3458 cli command
3459 """
3460 try:
3461 cmdStr = "app-ids"
3462 if jsonFormat:
3463 cmdStr += " -j"
3464 output = self.sendline( cmdStr )
3465 assert "Command not found:" not in output, output
3466 assert "Error executing command" not in output, output
3467 return output
3468 except AssertionError:
3469 main.log.exception( "Error in processing onos:app-ids command." )
3470 return None
3471 except TypeError:
3472 main.log.exception( self.name + ": Object not as expected" )
3473 return None
3474 except pexpect.EOF:
3475 main.log.error( self.name + ": EOF exception found" )
3476 main.log.error( self.name + ": " + self.handle.before )
3477 main.cleanup()
3478 main.exit()
3479 except Exception:
3480 main.log.exception( self.name + ": Uncaught exception!" )
3481 main.cleanup()
3482 main.exit()
3483
3484 def appToIDCheck( self ):
3485 """
3486 This method will check that each application's ID listed in 'apps' is
3487 the same as the ID listed in 'app-ids'. The check will also check that
3488 there are no duplicate IDs issued. Note that an app ID should be
3489 a globaly unique numerical identifier for app/app-like features. Once
3490 an ID is registered, the ID is never freed up so that if an app is
3491 reinstalled it will have the same ID.
3492
3493 Returns: main.TRUE if the check passes and
3494 main.FALSE if the check fails or
3495 main.ERROR if there is some error in processing the test
3496 """
3497 try:
3498 bail = False
3499 rawJson = self.appIDs( jsonFormat=True )
3500 if rawJson:
3501 ids = json.loads( rawJson )
3502 else:
3503 main.log.error( "app-ids returned nothing:" + repr( rawJson ) )
3504 bail = True
3505 rawJson = self.apps( jsonFormat=True )
3506 if rawJson:
3507 apps = json.loads( rawJson )
3508 else:
3509 main.log.error( "apps returned nothing:" + repr( rawJson ) )
3510 bail = True
3511 if bail:
3512 return main.FALSE
3513 result = main.TRUE
3514 for app in apps:
3515 appID = app.get( 'id' )
3516 if appID is None:
3517 main.log.error( "Error parsing app: " + str( app ) )
3518 result = main.FALSE
3519 appName = app.get( 'name' )
3520 if appName is None:
3521 main.log.error( "Error parsing app: " + str( app ) )
3522 result = main.FALSE
3523 # get the entry in ids that has the same appID
3524 current = filter( lambda item: item[ 'id' ] == appID, ids )
3525 # main.log.debug( "Comparing " + str( app ) + " to " +
3526 # str( current ) )
3527 if not current: # if ids doesn't have this id
3528 result = main.FALSE
3529 main.log.error( "'app-ids' does not have the ID for " +
3530 str( appName ) + " that apps does." )
3531 elif len( current ) > 1:
3532 # there is more than one app with this ID
3533 result = main.FALSE
3534 # We will log this later in the method
3535 elif not current[0][ 'name' ] == appName:
3536 currentName = current[0][ 'name' ]
3537 result = main.FALSE
3538 main.log.error( "'app-ids' has " + str( currentName ) +
3539 " registered under id:" + str( appID ) +
3540 " but 'apps' has " + str( appName ) )
3541 else:
3542 pass # id and name match!
3543 # now make sure that app-ids has no duplicates
3544 idsList = []
3545 namesList = []
3546 for item in ids:
3547 idsList.append( item[ 'id' ] )
3548 namesList.append( item[ 'name' ] )
3549 if len( idsList ) != len( set( idsList ) ) or\
3550 len( namesList ) != len( set( namesList ) ):
3551 main.log.error( "'app-ids' has some duplicate entries: \n"
3552 + json.dumps( ids,
3553 sort_keys=True,
3554 indent=4,
3555 separators=( ',', ': ' ) ) )
3556 result = main.FALSE
3557 return result
3558 except ( TypeError, ValueError ):
3559 main.log.exception( "{}: Object not as expected: {!r}".format( self.name, rawJson ) )
3560 return main.ERROR
3561 except pexpect.EOF:
3562 main.log.error( self.name + ": EOF exception found" )
3563 main.log.error( self.name + ": " + self.handle.before )
3564 main.cleanup()
3565 main.exit()
3566 except Exception:
3567 main.log.exception( self.name + ": Uncaught exception!" )
3568 main.cleanup()
3569 main.exit()
3570
3571 def getCfg( self, component=None, propName=None, short=False,
3572 jsonFormat=True ):
3573 """
3574 Get configuration settings from onos cli
3575 Optional arguments:
3576 component - Optionally only list configurations for a specific
3577 component. If None, all components with configurations
3578 are displayed. Case Sensitive string.
3579 propName - If component is specified, propName option will show
3580 only this specific configuration from that component.
3581 Case Sensitive string.
3582 jsonFormat - Returns output as json. Note that this will override
3583 the short option
3584 short - Short, less verbose, version of configurations.
3585 This is overridden by the json option
3586 returns:
3587 Output from cli as a string or None on error
3588 """
3589 try:
3590 baseStr = "cfg"
3591 cmdStr = " get"
3592 componentStr = ""
3593 if component:
3594 componentStr += " " + component
3595 if propName:
3596 componentStr += " " + propName
3597 if jsonFormat:
3598 baseStr += " -j"
3599 elif short:
3600 baseStr += " -s"
3601 output = self.sendline( baseStr + cmdStr + componentStr )
3602 assert "Command not found:" not in output, output
3603 assert "Error executing command" not in output, output
3604 return output
3605 except AssertionError:
3606 main.log.exception( "Error in processing 'cfg get' command." )
3607 return None
3608 except TypeError:
3609 main.log.exception( self.name + ": Object not as expected" )
3610 return None
3611 except pexpect.EOF:
3612 main.log.error( self.name + ": EOF exception found" )
3613 main.log.error( self.name + ": " + self.handle.before )
3614 main.cleanup()
3615 main.exit()
3616 except Exception:
3617 main.log.exception( self.name + ": Uncaught exception!" )
3618 main.cleanup()
3619 main.exit()
3620
3621 def setCfg( self, component, propName, value=None, check=True ):
3622 """
3623 Set/Unset configuration settings from ONOS cli
3624 Required arguments:
3625 component - The case sensitive name of the component whose
3626 property is to be set
3627 propName - The case sensitive name of the property to be set/unset
3628 Optional arguments:
3629 value - The value to set the property to. If None, will unset the
3630 property and revert it to it's default value(if applicable)
3631 check - Boolean, Check whether the option was successfully set this
3632 only applies when a value is given.
3633 returns:
3634 main.TRUE on success or main.FALSE on failure. If check is False,
3635 will return main.TRUE unless there is an error
3636 """
3637 try:
3638 baseStr = "cfg"
3639 cmdStr = " set " + str( component ) + " " + str( propName )
3640 if value is not None:
3641 cmdStr += " " + str( value )
3642 output = self.sendline( baseStr + cmdStr )
3643 assert "Command not found:" not in output, output
3644 assert "Error executing command" not in output, output
3645 if value and check:
3646 results = self.getCfg( component=str( component ),
3647 propName=str( propName ),
3648 jsonFormat=True )
3649 # Check if current value is what we just set
3650 try:
3651 jsonOutput = json.loads( results )
3652 current = jsonOutput[ 'value' ]
3653 except ( TypeError, ValueError ):
3654 main.log.exception( "Error parsing cfg output" )
3655 main.log.error( "output:" + repr( results ) )
3656 return main.FALSE
3657 if current == str( value ):
3658 return main.TRUE
3659 return main.FALSE
3660 return main.TRUE
3661 except AssertionError:
3662 main.log.exception( "Error in processing 'cfg set' command." )
3663 return main.FALSE
3664 except ( TypeError, ValueError ):
3665 main.log.exception( "{}: Object not as expected: {!r}".format( self.name, results ) )
3666 return main.FALSE
3667 except pexpect.EOF:
3668 main.log.error( self.name + ": EOF exception found" )
3669 main.log.error( self.name + ": " + self.handle.before )
3670 main.cleanup()
3671 main.exit()
3672 except Exception:
3673 main.log.exception( self.name + ": Uncaught exception!" )
3674 main.cleanup()
3675 main.exit()
3676
3677 def setTestAdd( self, setName, values ):
3678 """
3679 CLI command to add elements to a distributed set.
3680 Arguments:
3681 setName - The name of the set to add to.
3682 values - The value(s) to add to the set, space seperated.
3683 Example usages:
3684 setTestAdd( "set1", "a b c" )
3685 setTestAdd( "set2", "1" )
3686 returns:
3687 main.TRUE on success OR
3688 main.FALSE if elements were already in the set OR
3689 main.ERROR on error
3690 """
3691 try:
3692 cmdStr = "set-test-add " + str( setName ) + " " + str( values )
3693 output = self.sendline( cmdStr )
3694 assert "Command not found:" not in output, output
3695 try:
3696 # TODO: Maybe make this less hardcoded
3697 # ConsistentMap Exceptions
3698 assert "org.onosproject.store.service" not in output
3699 # Node not leader
3700 assert "java.lang.IllegalStateException" not in output
3701 except AssertionError:
3702 main.log.error( "Error in processing '" + cmdStr + "' " +
3703 "command: " + str( output ) )
3704 retryTime = 30 # Conservative time, given by Madan
3705 main.log.info( "Waiting " + str( retryTime ) +
3706 "seconds before retrying." )
3707 time.sleep( retryTime ) # Due to change in mastership
3708 output = self.sendline( cmdStr )
3709 assert "Error executing command" not in output
3710 positiveMatch = "\[(.*)\] was added to the set " + str( setName )
3711 negativeMatch = "\[(.*)\] was already in set " + str( setName )
3712 main.log.info( self.name + ": " + output )
3713 if re.search( positiveMatch, output):
3714 return main.TRUE
3715 elif re.search( negativeMatch, output):
3716 return main.FALSE
3717 else:
3718 main.log.error( self.name + ": setTestAdd did not" +
3719 " match expected output" )
3720 main.log.debug( self.name + " actual: " + repr( output ) )
3721 return main.ERROR
3722 except AssertionError:
3723 main.log.exception( "Error in processing '" + cmdStr + "' command. " )
3724 return main.ERROR
3725 except TypeError:
3726 main.log.exception( self.name + ": Object not as expected" )
3727 return main.ERROR
3728 except pexpect.EOF:
3729 main.log.error( self.name + ": EOF exception found" )
3730 main.log.error( self.name + ": " + self.handle.before )
3731 main.cleanup()
3732 main.exit()
3733 except Exception:
3734 main.log.exception( self.name + ": Uncaught exception!" )
3735 main.cleanup()
3736 main.exit()
3737
3738 def setTestRemove( self, setName, values, clear=False, retain=False ):
3739 """
3740 CLI command to remove elements from a distributed set.
3741 Required arguments:
3742 setName - The name of the set to remove from.
3743 values - The value(s) to remove from the set, space seperated.
3744 Optional arguments:
3745 clear - Clear all elements from the set
3746 retain - Retain only the given values. (intersection of the
3747 original set and the given set)
3748 returns:
3749 main.TRUE on success OR
3750 main.FALSE if the set was not changed OR
3751 main.ERROR on error
3752 """
3753 try:
3754 cmdStr = "set-test-remove "
3755 if clear:
3756 cmdStr += "-c " + str( setName )
3757 elif retain:
3758 cmdStr += "-r " + str( setName ) + " " + str( values )
3759 else:
3760 cmdStr += str( setName ) + " " + str( values )
3761 output = self.sendline( cmdStr )
3762 try:
3763 # TODO: Maybe make this less hardcoded
3764 # ConsistentMap Exceptions
3765 assert "org.onosproject.store.service" not in output
3766 # Node not leader
3767 assert "java.lang.IllegalStateException" not in output
3768 except AssertionError:
3769 main.log.error( "Error in processing '" + cmdStr + "' " +
3770 "command: " + str( output ) )
3771 retryTime = 30 # Conservative time, given by Madan
3772 main.log.info( "Waiting " + str( retryTime ) +
3773 "seconds before retrying." )
3774 time.sleep( retryTime ) # Due to change in mastership
3775 output = self.sendline( cmdStr )
3776 assert "Command not found:" not in output, output
3777 assert "Error executing command" not in output, output
3778 main.log.info( self.name + ": " + output )
3779 if clear:
3780 pattern = "Set " + str( setName ) + " cleared"
3781 if re.search( pattern, output ):
3782 return main.TRUE
3783 elif retain:
3784 positivePattern = str( setName ) + " was pruned to contain " +\
3785 "only elements of set \[(.*)\]"
3786 negativePattern = str( setName ) + " was not changed by " +\
3787 "retaining only elements of the set " +\
3788 "\[(.*)\]"
3789 if re.search( positivePattern, output ):
3790 return main.TRUE
3791 elif re.search( negativePattern, output ):
3792 return main.FALSE
3793 else:
3794 positivePattern = "\[(.*)\] was removed from the set " +\
3795 str( setName )
3796 if ( len( values.split() ) == 1 ):
3797 negativePattern = "\[(.*)\] was not in set " +\
3798 str( setName )
3799 else:
3800 negativePattern = "No element of \[(.*)\] was in set " +\
3801 str( setName )
3802 if re.search( positivePattern, output ):
3803 return main.TRUE
3804 elif re.search( negativePattern, output ):
3805 return main.FALSE
3806 main.log.error( self.name + ": setTestRemove did not" +
3807 " match expected output" )
3808 main.log.debug( self.name + " expected: " + pattern )
3809 main.log.debug( self.name + " actual: " + repr( output ) )
3810 return main.ERROR
3811 except AssertionError:
3812 main.log.exception( "Error in processing '" + cmdStr + "' commandr. " )
3813 return main.ERROR
3814 except TypeError:
3815 main.log.exception( self.name + ": Object not as expected" )
3816 return main.ERROR
3817 except pexpect.EOF:
3818 main.log.error( self.name + ": EOF exception found" )
3819 main.log.error( self.name + ": " + self.handle.before )
3820 main.cleanup()
3821 main.exit()
3822 except Exception:
3823 main.log.exception( self.name + ": Uncaught exception!" )
3824 main.cleanup()
3825 main.exit()
3826
3827 def setTestGet( self, setName, values="" ):
3828 """
3829 CLI command to get the elements in a distributed set.
3830 Required arguments:
3831 setName - The name of the set to remove from.
3832 Optional arguments:
3833 values - The value(s) to check if in the set, space seperated.
3834 returns:
3835 main.ERROR on error OR
3836 A list of elements in the set if no optional arguments are
3837 supplied OR
3838 A tuple containing the list then:
3839 main.FALSE if the given values are not in the set OR
3840 main.TRUE if the given values are in the set OR
3841 """
3842 try:
3843 values = str( values ).strip()
3844 setName = str( setName ).strip()
3845 length = len( values.split() )
3846 containsCheck = None
3847 # Patterns to match
3848 setPattern = "\[(.*)\]"
3849 pattern = "Items in set " + setName + ":\n" + setPattern
3850 containsTrue = "Set " + setName + " contains the value " + values
3851 containsFalse = "Set " + setName + " did not contain the value " +\
3852 values
3853 containsAllTrue = "Set " + setName + " contains the the subset " +\
3854 setPattern
3855 containsAllFalse = "Set " + setName + " did not contain the the" +\
3856 " subset " + setPattern
3857
3858 cmdStr = "set-test-get "
3859 cmdStr += setName + " " + values
3860 output = self.sendline( cmdStr )
3861 try:
3862 # TODO: Maybe make this less hardcoded
3863 # ConsistentMap Exceptions
3864 assert "org.onosproject.store.service" not in output
3865 # Node not leader
3866 assert "java.lang.IllegalStateException" not in output
3867 except AssertionError:
3868 main.log.error( "Error in processing '" + cmdStr + "' " +
3869 "command: " + str( output ) )
3870 retryTime = 30 # Conservative time, given by Madan
3871 main.log.info( "Waiting " + str( retryTime ) +
3872 "seconds before retrying." )
3873 time.sleep( retryTime ) # Due to change in mastership
3874 output = self.sendline( cmdStr )
3875 assert "Command not found:" not in output, output
3876 assert "Error executing command" not in output, output
3877 main.log.info( self.name + ": " + output )
3878
3879 if length == 0:
3880 match = re.search( pattern, output )
3881 else: # if given values
3882 if length == 1: # Contains output
3883 patternTrue = pattern + "\n" + containsTrue
3884 patternFalse = pattern + "\n" + containsFalse
3885 else: # ContainsAll output
3886 patternTrue = pattern + "\n" + containsAllTrue
3887 patternFalse = pattern + "\n" + containsAllFalse
3888 matchTrue = re.search( patternTrue, output )
3889 matchFalse = re.search( patternFalse, output )
3890 if matchTrue:
3891 containsCheck = main.TRUE
3892 match = matchTrue
3893 elif matchFalse:
3894 containsCheck = main.FALSE
3895 match = matchFalse
3896 else:
3897 main.log.error( self.name + " setTestGet did not match " +\
3898 "expected output" )
3899 main.log.debug( self.name + " expected: " + pattern )
3900 main.log.debug( self.name + " actual: " + repr( output ) )
3901 match = None
3902 if match:
3903 setMatch = match.group( 1 )
3904 if setMatch == '':
3905 setList = []
3906 else:
3907 setList = setMatch.split( ", " )
3908 if length > 0:
3909 return ( setList, containsCheck )
3910 else:
3911 return setList
3912 else: # no match
3913 main.log.error( self.name + ": setTestGet did not" +
3914 " match expected output" )
3915 main.log.debug( self.name + " expected: " + pattern )
3916 main.log.debug( self.name + " actual: " + repr( output ) )
3917 return main.ERROR
3918 except AssertionError:
3919 main.log.exception( "Error in processing '" + cmdStr + "' command." )
3920 return main.ERROR
3921 except TypeError:
3922 main.log.exception( self.name + ": Object not as expected" )
3923 return main.ERROR
3924 except pexpect.EOF:
3925 main.log.error( self.name + ": EOF exception found" )
3926 main.log.error( self.name + ": " + self.handle.before )
3927 main.cleanup()
3928 main.exit()
3929 except Exception:
3930 main.log.exception( self.name + ": Uncaught exception!" )
3931 main.cleanup()
3932 main.exit()
3933
3934 def setTestSize( self, setName ):
3935 """
3936 CLI command to get the elements in a distributed set.
3937 Required arguments:
3938 setName - The name of the set to remove from.
3939 returns:
3940 The integer value of the size returned or
3941 None on error
3942 """
3943 try:
3944 # TODO: Should this check against the number of elements returned
3945 # and then return true/false based on that?
3946 setName = str( setName ).strip()
3947 # Patterns to match
3948 setPattern = "\[(.*)\]"
3949 pattern = "There are (\d+) items in set " + setName + ":\n" +\
3950 setPattern
3951 cmdStr = "set-test-get -s "
3952 cmdStr += setName
3953 output = self.sendline( cmdStr )
3954 try:
3955 # TODO: Maybe make this less hardcoded
3956 # ConsistentMap Exceptions
3957 assert "org.onosproject.store.service" not in output
3958 # Node not leader
3959 assert "java.lang.IllegalStateException" not in output
3960 except AssertionError:
3961 main.log.error( "Error in processing '" + cmdStr + "' " +
3962 "command: " + str( output ) )
3963 retryTime = 30 # Conservative time, given by Madan
3964 main.log.info( "Waiting " + str( retryTime ) +
3965 "seconds before retrying." )
3966 time.sleep( retryTime ) # Due to change in mastership
3967 output = self.sendline( cmdStr )
3968 assert "Command not found:" not in output, output
3969 assert "Error executing command" not in output, output
3970 main.log.info( self.name + ": " + output )
3971 match = re.search( pattern, output )
3972 if match:
3973 setSize = int( match.group( 1 ) )
3974 setMatch = match.group( 2 )
3975 if len( setMatch.split() ) == setSize:
3976 main.log.info( "The size returned by " + self.name +
3977 " matches the number of elements in " +
3978 "the returned set" )
3979 else:
3980 main.log.error( "The size returned by " + self.name +
3981 " does not match the number of " +
3982 "elements in the returned set." )
3983 return setSize
3984 else: # no match
3985 main.log.error( self.name + ": setTestGet did not" +
3986 " match expected output" )
3987 main.log.debug( self.name + " expected: " + pattern )
3988 main.log.debug( self.name + " actual: " + repr( output ) )
3989 return None
3990 except AssertionError:
3991 main.log.exception( "Error in processing '" + cmdStr + "' command." )
3992 return None
3993 except TypeError:
3994 main.log.exception( self.name + ": Object not as expected" )
3995 return None
3996 except pexpect.EOF:
3997 main.log.error( self.name + ": EOF exception found" )
3998 main.log.error( self.name + ": " + self.handle.before )
3999 main.cleanup()
4000 main.exit()
4001 except Exception:
4002 main.log.exception( self.name + ": Uncaught exception!" )
4003 main.cleanup()
4004 main.exit()
4005
4006 def counters( self, jsonFormat=True ):
4007 """
4008 Command to list the various counters in the system.
4009 returns:
4010 if jsonFormat, a string of the json object returned by the cli
4011 command
4012 if not jsonFormat, the normal string output of the cli command
4013 None on error
4014 """
4015 try:
4016 counters = {}
4017 cmdStr = "counters"
4018 if jsonFormat:
4019 cmdStr += " -j"
4020 output = self.sendline( cmdStr )
4021 assert "Command not found:" not in output, output
4022 assert "Error executing command" not in output, output
4023 main.log.info( self.name + ": " + output )
4024 return output
4025 except AssertionError:
4026 main.log.exception( "Error in processing 'counters' command." )
4027 return None
4028 except TypeError:
4029 main.log.exception( self.name + ": Object not as expected" )
4030 return None
4031 except pexpect.EOF:
4032 main.log.error( self.name + ": EOF exception found" )
4033 main.log.error( self.name + ": " + self.handle.before )
4034 main.cleanup()
4035 main.exit()
4036 except Exception:
4037 main.log.exception( self.name + ": Uncaught exception!" )
4038 main.cleanup()
4039 main.exit()
4040
4041 def counterTestAddAndGet( self, counter, delta=1, inMemory=False ):
4042 """
4043 CLI command to add a delta to then get a distributed counter.
4044 Required arguments:
4045 counter - The name of the counter to increment.
4046 Optional arguments:
4047 delta - The long to add to the counter
4048 inMemory - use in memory map for the counter
4049 returns:
4050 integer value of the counter or
4051 None on Error
4052 """
4053 try:
4054 counter = str( counter )
4055 delta = int( delta )
4056 cmdStr = "counter-test-increment "
4057 if inMemory:
4058 cmdStr += "-i "
4059 cmdStr += counter
4060 if delta != 1:
4061 cmdStr += " " + str( delta )
4062 output = self.sendline( cmdStr )
4063 try:
4064 # TODO: Maybe make this less hardcoded
4065 # ConsistentMap Exceptions
4066 assert "org.onosproject.store.service" not in output
4067 # Node not leader
4068 assert "java.lang.IllegalStateException" not in output
4069 except AssertionError:
4070 main.log.error( "Error in processing '" + cmdStr + "' " +
4071 "command: " + str( output ) )
4072 retryTime = 30 # Conservative time, given by Madan
4073 main.log.info( "Waiting " + str( retryTime ) +
4074 "seconds before retrying." )
4075 time.sleep( retryTime ) # Due to change in mastership
4076 output = self.sendline( cmdStr )
4077 assert "Command not found:" not in output, output
4078 assert "Error executing command" not in output, output
4079 main.log.info( self.name + ": " + output )
4080 pattern = counter + " was updated to (-?\d+)"
4081 match = re.search( pattern, output )
4082 if match:
4083 return int( match.group( 1 ) )
4084 else:
4085 main.log.error( self.name + ": counterTestAddAndGet did not" +
4086 " match expected output." )
4087 main.log.debug( self.name + " expected: " + pattern )
4088 main.log.debug( self.name + " actual: " + repr( output ) )
4089 return None
4090 except AssertionError:
4091 main.log.exception( "Error in processing '" + cmdStr + "' command." )
4092 return None
4093 except TypeError:
4094 main.log.exception( self.name + ": Object not as expected" )
4095 return None
4096 except pexpect.EOF:
4097 main.log.error( self.name + ": EOF exception found" )
4098 main.log.error( self.name + ": " + self.handle.before )
4099 main.cleanup()
4100 main.exit()
4101 except Exception:
4102 main.log.exception( self.name + ": Uncaught exception!" )
4103 main.cleanup()
4104 main.exit()
4105
4106 def counterTestGetAndAdd( self, counter, delta=1, inMemory=False ):
4107 """
4108 CLI command to get a distributed counter then add a delta to it.
4109 Required arguments:
4110 counter - The name of the counter to increment.
4111 Optional arguments:
4112 delta - The long to add to the counter
4113 inMemory - use in memory map for the counter
4114 returns:
4115 integer value of the counter or
4116 None on Error
4117 """
4118 try:
4119 counter = str( counter )
4120 delta = int( delta )
4121 cmdStr = "counter-test-increment -g "
4122 if inMemory:
4123 cmdStr += "-i "
4124 cmdStr += counter
4125 if delta != 1:
4126 cmdStr += " " + str( delta )
4127 output = self.sendline( cmdStr )
4128 try:
4129 # TODO: Maybe make this less hardcoded
4130 # ConsistentMap Exceptions
4131 assert "org.onosproject.store.service" not in output
4132 # Node not leader
4133 assert "java.lang.IllegalStateException" not in output
4134 except AssertionError:
4135 main.log.error( "Error in processing '" + cmdStr + "' " +
4136 "command: " + str( output ) )
4137 retryTime = 30 # Conservative time, given by Madan
4138 main.log.info( "Waiting " + str( retryTime ) +
4139 "seconds before retrying." )
4140 time.sleep( retryTime ) # Due to change in mastership
4141 output = self.sendline( cmdStr )
4142 assert "Command not found:" not in output, output
4143 assert "Error executing command" not in output, output
4144 main.log.info( self.name + ": " + output )
4145 pattern = counter + " was updated to (-?\d+)"
4146 match = re.search( pattern, output )
4147 if match:
4148 return int( match.group( 1 ) )
4149 else:
4150 main.log.error( self.name + ": counterTestGetAndAdd did not" +
4151 " match expected output." )
4152 main.log.debug( self.name + " expected: " + pattern )
4153 main.log.debug( self.name + " actual: " + repr( output ) )
4154 return None
4155 except AssertionError:
4156 main.log.exception( "Error in processing '" + cmdStr + "' command." )
4157 return None
4158 except TypeError:
4159 main.log.exception( self.name + ": Object not as expected" )
4160 return None
4161 except pexpect.EOF:
4162 main.log.error( self.name + ": EOF exception found" )
4163 main.log.error( self.name + ": " + self.handle.before )
4164 main.cleanup()
4165 main.exit()
4166 except Exception:
4167 main.log.exception( self.name + ": Uncaught exception!" )
4168 main.cleanup()
4169 main.exit()
4170
4171 def summary( self, jsonFormat=True ):
4172 """
4173 Description: Execute summary command in onos
4174 Returns: json object ( summary -j ), returns main.FALSE if there is
4175 no output
4176
4177 """
4178 try:
4179 cmdStr = "summary"
4180 if jsonFormat:
4181 cmdStr += " -j"
4182 handle = self.sendline( cmdStr )
4183 assert "Command not found:" not in handle, handle
4184 assert "Error:" not in handle, handle
4185 if not handle:
4186 main.log.error( self.name + ": There is no output in " +
4187 "summary command" )
4188 return main.FALSE
4189 return handle
4190 except AssertionError:
4191 main.log.exception( "{} Error in summary output:".format( self.name ) )
4192 return None
4193 except TypeError:
4194 main.log.exception( self.name + ": Object not as expected" )
4195 return None
4196 except pexpect.EOF:
4197 main.log.error( self.name + ": EOF exception found" )
4198 main.log.error( self.name + ": " + self.handle.before )
4199 main.cleanup()
4200 main.exit()
4201 except Exception:
4202 main.log.exception( self.name + ": Uncaught exception!" )
4203 main.cleanup()
4204 main.exit()
4205
4206 def transactionalMapGet( self, keyName, inMemory=False ):
4207 """
4208 CLI command to get the value of a key in a consistent map using
4209 transactions. This a test function and can only get keys from the
4210 test map hard coded into the cli command
4211 Required arguments:
4212 keyName - The name of the key to get
4213 Optional arguments:
4214 inMemory - use in memory map for the counter
4215 returns:
4216 The string value of the key or
4217 None on Error
4218 """
4219 try:
4220 keyName = str( keyName )
4221 cmdStr = "transactional-map-test-get "
4222 if inMemory:
4223 cmdStr += "-i "
4224 cmdStr += keyName
4225 output = self.sendline( cmdStr )
4226 assert "Command not found:" not in output, output
4227 try:
4228 # TODO: Maybe make this less hardcoded
4229 # ConsistentMap Exceptions
4230 assert "org.onosproject.store.service" not in output
4231 # Node not leader
4232 assert "java.lang.IllegalStateException" not in output
4233 except AssertionError:
4234 main.log.error( "Error in processing '" + cmdStr + "' " +
4235 "command: " + str( output ) )
4236 return None
4237 pattern = "Key-value pair \(" + keyName + ", (?P<value>.+)\) found."
4238 if "Key " + keyName + " not found." in output:
4239 return None
4240 else:
4241 match = re.search( pattern, output )
4242 if match:
4243 return match.groupdict()[ 'value' ]
4244 else:
4245 main.log.error( self.name + ": transactionlMapGet did not" +
4246 " match expected output." )
4247 main.log.debug( self.name + " expected: " + pattern )
4248 main.log.debug( self.name + " actual: " + repr( output ) )
4249 return None
4250 except AssertionError:
4251 main.log.exception( "" )
4252 return None
4253 except TypeError:
4254 main.log.exception( self.name + ": Object not as expected" )
4255 return None
4256 except pexpect.EOF:
4257 main.log.error( self.name + ": EOF exception found" )
4258 main.log.error( self.name + ": " + self.handle.before )
4259 main.cleanup()
4260 main.exit()
4261 except Exception:
4262 main.log.exception( self.name + ": Uncaught exception!" )
4263 main.cleanup()
4264 main.exit()
4265
4266 def transactionalMapPut( self, numKeys, value, inMemory=False ):
4267 """
4268 CLI command to put a value into 'numKeys' number of keys in a
4269 consistent map using transactions. This a test function and can only
4270 put into keys named 'Key#' of the test map hard coded into the cli command
4271 Required arguments:
4272 numKeys - Number of keys to add the value to
4273 value - The string value to put into the keys
4274 Optional arguments:
4275 inMemory - use in memory map for the counter
4276 returns:
4277 A dictionary whose keys are the name of the keys put into the map
4278 and the values of the keys are dictionaries whose key-values are
4279 'value': value put into map and optionaly
4280 'oldValue': Previous value in the key or
4281 None on Error
4282
4283 Example output
4284 { 'Key1': {'oldValue': 'oldTestValue', 'value': 'Testing'},
4285 'Key2': {'value': 'Testing'} }
4286 """
4287 try:
4288 numKeys = str( numKeys )
4289 value = str( value )
4290 cmdStr = "transactional-map-test-put "
4291 if inMemory:
4292 cmdStr += "-i "
4293 cmdStr += numKeys + " " + value
4294 output = self.sendline( cmdStr )
4295 assert "Command not found:" not in output, output
4296 try:
4297 # TODO: Maybe make this less hardcoded
4298 # ConsistentMap Exceptions
4299 assert "org.onosproject.store.service" not in output
4300 # Node not leader
4301 assert "java.lang.IllegalStateException" not in output
4302 except AssertionError:
4303 main.log.error( "Error in processing '" + cmdStr + "' " +
4304 "command: " + str( output ) )
4305 return None
4306 newPattern = 'Created Key (?P<key>(\w)+) with value (?P<value>(.)+)\.'
4307 updatedPattern = "Put (?P<value>(.)+) into key (?P<key>(\w)+)\. The old value was (?P<oldValue>(.)+)\."
4308 results = {}
4309 for line in output.splitlines():
4310 new = re.search( newPattern, line )
4311 updated = re.search( updatedPattern, line )
4312 if new:
4313 results[ new.groupdict()[ 'key' ] ] = { 'value': new.groupdict()[ 'value' ] }
4314 elif updated:
4315 results[ updated.groupdict()[ 'key' ] ] = { 'value': updated.groupdict()[ 'value' ],
4316 'oldValue': updated.groupdict()[ 'oldValue' ] }
4317 else:
4318 main.log.error( self.name + ": transactionlMapGet did not" +
4319 " match expected output." )
4320 main.log.debug( "{} expected: {!r} or {!r}".format( self.name,
4321 newPattern,
4322 updatedPattern ) )
4323 main.log.debug( self.name + " actual: " + repr( output ) )
4324 return results
4325 except AssertionError:
4326 main.log.exception( "" )
4327 return None
4328 except TypeError:
4329 main.log.exception( self.name + ": Object not as expected" )
4330 return None
4331 except pexpect.EOF:
4332 main.log.error( self.name + ": EOF exception found" )
4333 main.log.error( self.name + ": " + self.handle.before )
4334 main.cleanup()
4335 main.exit()
4336 except Exception:
4337 main.log.exception( self.name + ": Uncaught exception!" )
4338 main.cleanup()
4339 main.exit()
4340
4341 def maps( self, jsonFormat=True ):
4342 """
4343 Description: Returns result of onos:maps
4344 Optional:
4345 * jsonFormat: enable json formatting of output
4346 """
4347 try:
4348 cmdStr = "maps"
4349 if jsonFormat:
4350 cmdStr += " -j"
4351 handle = self.sendline( cmdStr )
4352 assert "Command not found:" not in handle, handle
4353 return handle
4354 except AssertionError:
4355 main.log.exception( "" )
4356 return None
4357 except TypeError:
4358 main.log.exception( self.name + ": Object not as expected" )
4359 return None
4360 except pexpect.EOF:
4361 main.log.error( self.name + ": EOF exception found" )
4362 main.log.error( self.name + ": " + self.handle.before )
4363 main.cleanup()
4364 main.exit()
4365 except Exception:
4366 main.log.exception( self.name + ": Uncaught exception!" )
4367 main.cleanup()
4368 main.exit()
4369
4370 def getSwController( self, uri, jsonFormat=True ):
4371 """
4372 Descrition: Gets the controller information from the device
4373 """
4374 try:
4375 cmd = "device-controllers "
4376 if jsonFormat:
4377 cmd += "-j "
4378 response = self.sendline( cmd + uri )
4379 assert "Command not found:" not in response, response
4380 return response
4381 except AssertionError:
4382 main.log.exception( "" )
4383 return None
4384 except TypeError:
4385 main.log.exception( self.name + ": Object not as expected" )
4386 return None
4387 except pexpect.EOF:
4388 main.log.error( self.name + ": EOF exception found" )
4389 main.log.error( self.name + ": " + self.handle.before )
4390 main.cleanup()
4391 main.exit()
4392 except Exception:
4393 main.log.exception( self.name + ": Uncaught exception!" )
4394 main.cleanup()
4395 main.exit()
4396
4397 def setSwController( self, uri, ip, proto="tcp", port="6653", jsonFormat=True ):
4398 """
4399 Descrition: sets the controller(s) for the specified device
4400
4401 Parameters:
4402 Required: uri - String: The uri of the device(switch).
4403 ip - String or List: The ip address of the controller.
4404 This parameter can be formed in a couple of different ways.
4405 VALID:
4406 10.0.0.1 - just the ip address
4407 tcp:10.0.0.1 - the protocol and the ip address
4408 tcp:10.0.0.1:6653 - the protocol and port can be specified,
4409 so that you can add controllers with different
4410 protocols and ports
4411 INVALID:
4412 10.0.0.1:6653 - this is not supported by ONOS
4413
4414 Optional: proto - The type of connection e.g. tcp, ssl. If a list of ips are given
4415 port - The port number.
4416 jsonFormat - If set ONOS will output in json NOTE: This is currently not supported
4417
4418 Returns: main.TRUE if ONOS returns without any errors, otherwise returns main.FALSE
4419 """
4420 try:
4421 cmd = "device-setcontrollers"
4422
4423 if jsonFormat:
4424 cmd += " -j"
4425 cmd += " " + uri
4426 if isinstance( ip, str ):
4427 ip = [ip]
4428 for item in ip:
4429 if ":" in item:
4430 sitem = item.split( ":" )
4431 if len(sitem) == 3:
4432 cmd += " " + item
4433 elif "." in sitem[1]:
4434 cmd += " {}:{}".format(item, port)
4435 else:
4436 main.log.error( "Malformed entry: " + item )
4437 raise TypeError
4438 else:
4439 cmd += " {}:{}:{}".format( proto, item, port )
4440 response = self.sendline( cmd )
4441 assert "Command not found:" not in response, response
4442 if "Error" in response:
4443 main.log.error( response )
4444 return main.FALSE
4445 return main.TRUE
4446 except AssertionError:
4447 main.log.exception( "" )
4448 return None
4449 except TypeError:
4450 main.log.exception( self.name + ": Object not as expected" )
4451 return main.FALSE
4452 except pexpect.EOF:
4453 main.log.error( self.name + ": EOF exception found" )
4454 main.log.error( self.name + ": " + self.handle.before )
4455 main.cleanup()
4456 main.exit()
4457 except Exception:
4458 main.log.exception( self.name + ": Uncaught exception!" )
4459 main.cleanup()
4460 main.exit()
4461
4462 def removeDevice( self, device ):
4463 '''
4464 Description:
4465 Remove a device from ONOS by passing the uri of the device(s).
4466 Parameters:
4467 device - (str or list) the id or uri of the device ex. "of:0000000000000001"
4468 Returns:
4469 Returns main.FALSE if an exception is thrown or an error is present
4470 in the response. Otherwise, returns main.TRUE.
4471 NOTE:
4472 If a host cannot be removed, then this function will return main.FALSE
4473 '''
4474 try:
4475 if type( device ) is str:
4476 device = list( device )
4477
4478 for d in device:
4479 time.sleep( 1 )
4480 response = self.sendline( "device-remove {}".format( d ) )
4481 assert "Command not found:" not in response, response
4482 if "Error" in response:
4483 main.log.warn( "Error for device: {}\nResponse: {}".format( d, response ) )
4484 return main.FALSE
4485 return main.TRUE
4486 except AssertionError:
4487 main.log.exception( "" )
4488 return main.FALSE
4489 except TypeError:
4490 main.log.exception( self.name + ": Object not as expected" )
4491 return main.FALSE
4492 except pexpect.EOF:
4493 main.log.error( self.name + ": EOF exception found" )
4494 main.log.error( self.name + ": " + self.handle.before )
4495 main.cleanup()
4496 main.exit()
4497 except Exception:
4498 main.log.exception( self.name + ": Uncaught exception!" )
4499 main.cleanup()
4500 main.exit()
4501
4502 def removeHost( self, host ):
4503 '''
4504 Description:
4505 Remove a host from ONOS by passing the id of the host(s)
4506 Parameters:
4507 hostId - (str or list) the id or mac of the host ex. "00:00:00:00:00:01"
4508 Returns:
4509 Returns main.FALSE if an exception is thrown or an error is present
4510 in the response. Otherwise, returns main.TRUE.
4511 NOTE:
4512 If a host cannot be removed, then this function will return main.FALSE
4513 '''
4514 try:
4515 if type( host ) is str:
4516 host = list( host )
4517
4518 for h in host:
4519 time.sleep( 1 )
4520 response = self.sendline( "host-remove {}".format( h ) )
4521 assert "Command not found:" not in response, response
4522 if "Error" in response:
4523 main.log.warn( "Error for host: {}\nResponse: {}".format( h, response ) )
4524 return main.FALSE
4525 return main.TRUE
4526 except AssertionError:
4527 main.log.exception( "" )
4528 return None
4529 except TypeError:
4530 main.log.exception( self.name + ": Object not as expected" )
4531 return main.FALSE
4532 except pexpect.EOF:
4533 main.log.error( self.name + ": EOF exception found" )
4534 main.log.error( self.name + ": " + self.handle.before )
4535 main.cleanup()
4536 main.exit()
4537 except Exception:
4538 main.log.exception( self.name + ": Uncaught exception!" )
4539 main.cleanup()
4540 main.exit()
4541
4542 def link( self, begin, end, state ):
4543 '''
4544 Description:
4545 Bring link down or up in the null-provider.
4546 params:
4547 begin - (string) One end of a device or switch.
4548 end - (string) the other end of the device or switch
4549 returns:
4550 main.TRUE if no exceptions were thrown and no Errors are
4551 present in the resoponse. Otherwise, returns main.FALSE
4552 '''
4553 try:
4554 cmd = "null-link null:{} null:{} {}".format( begin, end, state )
4555 response = self.sendline( cmd, showResponse=True )
4556 assert "Command not found:" not in response, response
4557 if "Error" in response or "Failure" in response:
4558 main.log.error( response )
4559 return main.FALSE
4560 return main.TRUE
4561 except AssertionError:
4562 main.log.exception( "" )
4563 return None
4564 except TypeError:
4565 main.log.exception( self.name + ": Object not as expected" )
4566 return main.FALSE
4567 except pexpect.EOF:
4568 main.log.error( self.name + ": EOF exception found" )
4569 main.log.error( self.name + ": " + self.handle.before )
4570 main.cleanup()
4571 main.exit()
4572 except Exception:
4573 main.log.exception( self.name + ": Uncaught exception!" )
4574 main.cleanup()
4575 main.exit()
4576
4577if __name__ == '__main__':
4578 onos_cli = OnosCliDriver()
4579 name = 'onos_cli'
4580 user = 'onos'
4581 passwd = 'rocks'
4582 ip = '172.17.0.2'
4583 options = { 'name': '{0}'.format(name), 'onosIp' : '{0}'.format(ip) }
4584 onos_cli.connect(name = 'onoscli', user_name = user, pwd = passwd, ip_address = ip,
4585 port = '8101', options = options)
4586 device_str = onos_cli.devices(jsonFormat = False)
4587 print('Devices: %s' %device_str)
4588 device_json = onos_cli.devices()
4589 print('Device json: %s' %device_json)
4590 routes_str = onos_cli.routes(jsonFormat = False)
4591 print('Routes %s' %routes_str)
4592 flows_json = onos_cli.flows(state = "ADDED")
4593 print('Flows %s' %flows_json)
4594 onos_cli.disconnect()
4595