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