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