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