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