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