blob: 4ea1fb677b789c1fd57e5cab65efba6a1087d801 [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
2192 def flows( self, state="", jsonFormat=True, timeout=60 ):
2193 """
2194 Optional:
2195 * jsonFormat: enable output formatting in json
2196 Description:
2197 Obtain flows currently installed
2198 """
2199 try:
2200 cmdStr = "flows"
2201 if jsonFormat:
2202 cmdStr += " -j "
2203 cmdStr += state
2204 handle = self.sendline( cmdStr, timeout=timeout )
2205 assert "Command not found:" not in handle, handle
2206 if re.search( "Error:", handle ):
2207 main.log.error( self.name + ": flows() response: " +
2208 str( handle ) )
2209 return handle
2210 except AssertionError:
2211 main.log.exception( "" )
2212 return None
2213 except TypeError:
2214 main.log.exception( self.name + ": Object not as expected" )
2215 return None
2216 except pexpect.TIMEOUT:
2217 main.log.error( self.name + ": ONOS timeout" )
2218 return None
2219 except pexpect.EOF:
2220 main.log.error( self.name + ": EOF exception found" )
2221 main.log.error( self.name + ": " + self.handle.before )
2222 main.cleanup()
2223 main.exit()
2224 except Exception:
2225 main.log.exception( self.name + ": Uncaught exception!" )
2226 main.cleanup()
2227 main.exit()
2228
2229
2230 def checkFlowsState( self, isPENDING=True, timeout=60 ):
2231 """
2232 Description:
2233 Check the if all the current flows are in ADDED state
2234 We check PENDING_ADD, PENDING_REMOVE, REMOVED, and FAILED flows,
2235 if the count of those states is 0, which means all current flows
2236 are in ADDED state, and return main.TRUE otherwise return main.FALSE
2237 Optional:
2238 * isPENDING: whether the PENDING_ADD is also a correct status
2239 Return:
2240 returnValue - Returns main.TRUE only if all flows are in
2241 ADDED state or PENDING_ADD if the isPENDING
2242 parameter is set true, return main.FALSE otherwise.
2243 """
2244 try:
2245 states = ["PENDING_ADD", "PENDING_REMOVE", "REMOVED", "FAILED"]
2246 checkedStates = []
2247 statesCount = [0, 0, 0, 0]
2248 for s in states:
2249 rawFlows = self.flows( state=s, timeout = timeout )
2250 checkedStates.append( json.loads( rawFlows ) )
2251 for i in range( len( states ) ):
2252 for c in checkedStates[i]:
2253 try:
2254 statesCount[i] += int( c.get( "flowCount" ) )
2255 except TypeError:
2256 main.log.exception( "Json object not as expected" )
2257 main.log.info( states[i] + " flows: " + str( statesCount[i] ) )
2258
2259 # We want to count PENDING_ADD if isPENDING is true
2260 if isPENDING:
2261 if statesCount[1] + statesCount[2] + statesCount[3] > 0:
2262 return main.FALSE
2263 else:
2264 if statesCount[0] + statesCount[1] + statesCount[2] + statesCount[3] > 0:
2265 return main.FALSE
2266 return main.TRUE
2267 except ( TypeError, ValueError ):
2268 main.log.exception( "{}: Object not as expected: {!r}".format( self.name, rawFlows ) )
2269 return None
2270 except pexpect.EOF:
2271 main.log.error( self.name + ": EOF exception found" )
2272 main.log.error( self.name + ": " + self.handle.before )
2273 main.cleanup()
2274 main.exit()
2275 except Exception:
2276 main.log.exception( self.name + ": Uncaught exception!" )
2277 main.cleanup()
2278 main.exit()
2279
2280 def pushTestIntents( self, ingress, egress, batchSize, offset="",
2281 options="", timeout=10, background = False ):
2282 """
2283 Description:
2284 Push a number of intents in a batch format to
2285 a specific point-to-point intent definition
2286 Required:
2287 * ingress: specify source dpid
2288 * egress: specify destination dpid
2289 * batchSize: specify number of intents to push
2290 Optional:
2291 * offset: the keyOffset is where the next batch of intents
2292 will be installed
2293 Returns: If failed to push test intents, it will returen None,
2294 if successful, return true.
2295 Timeout expection will return None,
2296 TypeError will return false
2297 other expections will exit()
2298 """
2299 try:
2300 if background:
2301 back = "&"
2302 else:
2303 back = ""
2304 cmd = "push-test-intents {} {} {} {} {} {}".format( options,
2305 ingress,
2306 egress,
2307 batchSize,
2308 offset,
2309 back )
2310 response = self.sendline( cmd, timeout=timeout )
2311 assert "Command not found:" not in response, response
2312 main.log.info( response )
2313 if response == None:
2314 return None
2315
2316 # TODO: We should handle if there is failure in installation
2317 return main.TRUE
2318
2319 except AssertionError:
2320 main.log.exception( "" )
2321 return None
2322 except pexpect.TIMEOUT:
2323 main.log.error( self.name + ": ONOS timeout" )
2324 return None
2325 except pexpect.EOF:
2326 main.log.error( self.name + ": EOF exception found" )
2327 main.log.error( self.name + ": " + self.handle.before )
2328 main.cleanup()
2329 main.exit()
2330 except TypeError:
2331 main.log.exception( self.name + ": Object not as expected" )
2332 return None
2333 except Exception:
2334 main.log.exception( self.name + ": Uncaught exception!" )
2335 main.cleanup()
2336 main.exit()
2337
2338 def getTotalFlowsNum( self, timeout=60 ):
2339 """
2340 Description:
2341 Get the number of ADDED flows.
2342 Return:
2343 The number of ADDED flows
2344 """
2345
2346 try:
2347 # get total added flows number
2348 cmd = "flows -s|grep ADDED|wc -l"
2349 totalFlows = self.sendline( cmd, timeout=timeout )
2350
2351 if totalFlows == None:
2352 # if timeout, we will get total number of all flows, and subtract other states
2353 states = ["PENDING_ADD", "PENDING_REMOVE", "REMOVED", "FAILED"]
2354 checkedStates = []
2355 totalFlows = 0
2356 statesCount = [0, 0, 0, 0]
2357
2358 # get total flows from summary
2359 response = json.loads( self.sendline( "summary -j", timeout=timeout ) )
2360 totalFlows = int( response.get("flows") )
2361
2362 for s in states:
2363 rawFlows = self.flows( state=s, timeout = timeout )
2364 if rawFlows == None:
2365 # if timeout, return the total flows number from summary command
2366 return totalFlows
2367 checkedStates.append( json.loads( rawFlows ) )
2368
2369 # Calculate ADDED flows number, equal total subtracts others
2370 for i in range( len( states ) ):
2371 for c in checkedStates[i]:
2372 try:
2373 statesCount[i] += int( c.get( "flowCount" ) )
2374 except TypeError:
2375 main.log.exception( "Json object not as expected" )
2376 totalFlows = totalFlows - int( statesCount[i] )
2377 main.log.info( states[i] + " flows: " + str( statesCount[i] ) )
2378
2379 return totalFlows
2380
2381 return totalFlows
2382
2383 except TypeError:
2384 main.log.exception( self.name + ": Object not as expected" )
2385 return None
2386 except pexpect.EOF:
2387 main.log.error( self.name + ": EOF exception found" )
2388 main.log.error( self.name + ": " + self.handle.before )
2389 main.cleanup()
2390 main.exit()
2391 except Exception:
2392 main.log.exception( self.name + ": Uncaught exception!" )
2393 main.cleanup()
2394 main.exit()
2395
2396 def getTotalIntentsNum( self ):
2397 """
2398 Description:
2399 Get the total number of intents, include every states.
2400 Return:
2401 The number of intents
2402 """
2403 try:
2404 cmd = "summary -j"
2405 response = self.sendline( cmd )
2406 if response == None:
2407 return -1
2408 response = json.loads( response )
2409 return int( response.get("intents") )
2410 except TypeError:
2411 main.log.exception( self.name + ": Object not as expected" )
2412 return None
2413 except pexpect.EOF:
2414 main.log.error( self.name + ": EOF exception found" )
2415 main.log.error( self.name + ": " + self.handle.before )
2416 main.cleanup()
2417 main.exit()
2418 except Exception:
2419 main.log.exception( self.name + ": Uncaught exception!" )
2420 main.cleanup()
2421 main.exit()
2422
2423 def intentsEventsMetrics( self, jsonFormat=True ):
2424 """
2425 Description:Returns topology metrics
2426 Optional:
2427 * jsonFormat: enable json formatting of output
2428 """
2429 try:
2430 cmdStr = "intents-events-metrics"
2431 if jsonFormat:
2432 cmdStr += " -j"
2433 handle = self.sendline( cmdStr )
2434 assert "Command not found:" not in handle, handle
2435 return handle
2436 except AssertionError:
2437 main.log.exception( "" )
2438 return None
2439 except TypeError:
2440 main.log.exception( self.name + ": Object not as expected" )
2441 return None
2442 except pexpect.EOF:
2443 main.log.error( self.name + ": EOF exception found" )
2444 main.log.error( self.name + ": " + self.handle.before )
2445 main.cleanup()
2446 main.exit()
2447 except Exception:
2448 main.log.exception( self.name + ": Uncaught exception!" )
2449 main.cleanup()
2450 main.exit()
2451
2452 def topologyEventsMetrics( self, jsonFormat=True ):
2453 """
2454 Description:Returns topology metrics
2455 Optional:
2456 * jsonFormat: enable json formatting of output
2457 """
2458 try:
2459 cmdStr = "topology-events-metrics"
2460 if jsonFormat:
2461 cmdStr += " -j"
2462 handle = self.sendline( cmdStr )
2463 assert "Command not found:" not in handle, handle
2464 if handle:
2465 return handle
2466 elif jsonFormat:
2467 # Return empty json
2468 return '{}'
2469 else:
2470 return handle
2471 except AssertionError:
2472 main.log.exception( "" )
2473 return None
2474 except TypeError:
2475 main.log.exception( self.name + ": Object not as expected" )
2476 return None
2477 except pexpect.EOF:
2478 main.log.error( self.name + ": EOF exception found" )
2479 main.log.error( self.name + ": " + self.handle.before )
2480 main.cleanup()
2481 main.exit()
2482 except Exception:
2483 main.log.exception( self.name + ": Uncaught exception!" )
2484 main.cleanup()
2485 main.exit()
2486
2487 # Wrapper functions ****************
2488 # Wrapper functions use existing driver
2489 # functions and extends their use case.
2490 # For example, we may use the output of
2491 # a normal driver function, and parse it
2492 # using a wrapper function
2493
2494 def getAllIntentsId( self ):
2495 """
2496 Description:
2497 Obtain all intent id's in a list
2498 """
2499 try:
2500 # Obtain output of intents function
2501 intentsStr = self.intents(jsonFormat=False)
2502 intentIdList = []
2503
2504 # Parse the intents output for ID's
2505 intentsList = [ s.strip() for s in intentsStr.splitlines() ]
2506 for intents in intentsList:
2507 match = re.search('id=0x([\da-f]+),', intents)
2508 if match:
2509 tmpId = match.group()[3:-1]
2510 intentIdList.append( tmpId )
2511 return intentIdList
2512
2513 except TypeError:
2514 main.log.exception( self.name + ": Object not as expected" )
2515 return None
2516 except pexpect.EOF:
2517 main.log.error( self.name + ": EOF exception found" )
2518 main.log.error( self.name + ": " + self.handle.before )
2519 main.cleanup()
2520 main.exit()
2521 except Exception:
2522 main.log.exception( self.name + ": Uncaught exception!" )
2523 main.cleanup()
2524 main.exit()
2525
2526 def FlowAddedCount( self, deviceId ):
2527 """
2528 Determine the number of flow rules for the given device id that are
2529 in the added state
2530 """
2531 try:
2532 cmdStr = "flows any " + str( deviceId ) + " | " +\
2533 "grep 'state=ADDED' | wc -l"
2534 handle = self.sendline( cmdStr )
2535 assert "Command not found:" not in handle, handle
2536 return handle
2537 except AssertionError:
2538 main.log.exception( "" )
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 def getAllDevicesId( self ):
2551 """
2552 Use 'devices' function to obtain list of all devices
2553 and parse the result to obtain a list of all device
2554 id's. Returns this list. Returns empty list if no
2555 devices exist
2556 List is ordered sequentially
2557
2558 This function may be useful if you are not sure of the
2559 device id, and wish to execute other commands using
2560 the ids. By obtaining the list of device ids on the fly,
2561 you can iterate through the list to get mastership, etc.
2562 """
2563 try:
2564 # Call devices and store result string
2565 devicesStr = self.devices( jsonFormat=False )
2566 idList = []
2567
2568 if not devicesStr:
2569 main.log.info( "There are no devices to get id from" )
2570 return idList
2571
2572 # Split the string into list by comma
2573 deviceList = devicesStr.split( "," )
2574 # Get temporary list of all arguments with string 'id='
2575 tempList = [ dev for dev in deviceList if "id=" in dev ]
2576 # Split list further into arguments before and after string
2577 # 'id='. Get the latter portion ( the actual device id ) and
2578 # append to idList
2579 for arg in tempList:
2580 idList.append( arg.split( "id=" )[ 1 ] )
2581 return idList
2582
2583 except TypeError:
2584 main.log.exception( self.name + ": Object not as expected" )
2585 return None
2586 except pexpect.EOF:
2587 main.log.error( self.name + ": EOF exception found" )
2588 main.log.error( self.name + ": " + self.handle.before )
2589 main.cleanup()
2590 main.exit()
2591 except Exception:
2592 main.log.exception( self.name + ": Uncaught exception!" )
2593 main.cleanup()
2594 main.exit()
2595
2596 def getAllNodesId( self ):
2597 """
2598 Uses 'nodes' function to obtain list of all nodes
2599 and parse the result of nodes to obtain just the
2600 node id's.
2601 Returns:
2602 list of node id's
2603 """
2604 try:
2605 nodesStr = self.nodes( jsonFormat=True )
2606 idList = []
2607 # Sample nodesStr output
2608 # id=local, address=127.0.0.1:9876, state=READY *
2609 if not nodesStr:
2610 main.log.info( "There are no nodes to get id from" )
2611 return idList
2612 nodesJson = json.loads( nodesStr )
2613 idList = [ node.get('id') for node in nodesJson ]
2614 return idList
2615 except ( TypeError, ValueError ):
2616 main.log.exception( "{}: Object not as expected: {!r}".format( self.name, nodesStr ) )
2617 return None
2618 except pexpect.EOF:
2619 main.log.error( self.name + ": EOF exception found" )
2620 main.log.error( self.name + ": " + self.handle.before )
2621 main.cleanup()
2622 main.exit()
2623 except Exception:
2624 main.log.exception( self.name + ": Uncaught exception!" )
2625 main.cleanup()
2626 main.exit()
2627
2628 def getDevice( self, dpid=None ):
2629 """
2630 Return the first device from the devices api whose 'id' contains 'dpid'
2631 Return None if there is no match
2632 """
2633 try:
2634 if dpid is None:
2635 return None
2636 else:
2637 dpid = dpid.replace( ':', '' )
2638 rawDevices = self.devices()
2639 devicesJson = json.loads( rawDevices )
2640 # search json for the device with dpid then return the device
2641 for device in devicesJson:
2642 # print "%s in %s?" % ( dpid, device[ 'id' ] )
2643 if dpid in device[ 'id' ]:
2644 return device
2645 return None
2646 except ( TypeError, ValueError ):
2647 main.log.exception( "{}: Object not as expected: {!r}".format( self.name, rawDevices ) )
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 checkStatus( self, ip, numoswitch, numolink, logLevel="info" ):
2660 """
2661 Checks the number of switches & links that ONOS sees against the
2662 supplied values. By default this will report to main.log, but the
2663 log level can be specified.
2664
2665 Params: ip = ip used for the onos cli
2666 numoswitch = expected number of switches
2667 numolink = expected number of links
2668 logLevel = level to log to. Currently accepts
2669 'info', 'warn' and 'report'
2670
2671
2672 logLevel can
2673
2674 Returns: main.TRUE if the number of switches and links are correct,
2675 main.FALSE if the number of switches and links is incorrect,
2676 and main.ERROR otherwise
2677 """
2678 try:
2679 topology = self.getTopology( ip )
2680 if topology == {}:
2681 return main.ERROR
2682 output = ""
2683 # Is the number of switches is what we expected
2684 devices = topology.get( 'devices', False )
2685 links = topology.get( 'links', False )
2686 if devices is False or links is False:
2687 return main.ERROR
2688 switchCheck = ( int( devices ) == int( numoswitch ) )
2689 # Is the number of links is what we expected
2690 linkCheck = ( int( links ) == int( numolink ) )
2691 if ( switchCheck and linkCheck ):
2692 # We expected the correct numbers
2693 output += "The number of links and switches match " +\
2694 "what was expected"
2695 result = main.TRUE
2696 else:
2697 output += "The number of links and switches does not match " +\
2698 "what was expected"
2699 result = main.FALSE
2700 output = output + "\n ONOS sees %i devices (%i expected) \
2701 and %i links (%i expected)" % (
2702 int( devices ), int( numoswitch ), int( links ),
2703 int( numolink ) )
2704 if logLevel == "report":
2705 main.log.report( output )
2706 elif logLevel == "warn":
2707 main.log.warn( output )
2708 else:
2709 main.log.info( self.name + ": " + output )
2710 return result
2711 except TypeError:
2712 main.log.exception( self.name + ": Object not as expected" )
2713 return None
2714 except pexpect.EOF:
2715 main.log.error( self.name + ": EOF exception found" )
2716 main.log.error( self.name + ": " + self.handle.before )
2717 main.cleanup()
2718 main.exit()
2719 except Exception:
2720 main.log.exception( self.name + ": Uncaught exception!" )
2721 main.cleanup()
2722 main.exit()
2723
2724 def deviceRole( self, deviceId, onosNode, role="master" ):
2725 """
2726 Calls the device-role cli command.
2727 deviceId must be the id of a device as seen in the onos devices command
2728 onosNode is the ip of one of the onos nodes in the cluster
2729 role must be either master, standby, or none
2730
2731 Returns:
2732 main.TRUE or main.FALSE based on argument verification and
2733 main.ERROR if command returns and error
2734 """
2735 try:
2736 if role.lower() == "master" or role.lower() == "standby" or\
2737 role.lower() == "none":
2738 cmdStr = "device-role " +\
2739 str( deviceId ) + " " +\
2740 str( onosNode ) + " " +\
2741 str( role )
2742 handle = self.sendline( cmdStr )
2743 assert "Command not found:" not in handle, handle
2744 if re.search( "Error", handle ):
2745 # end color output to escape any colours
2746 # from the cli
2747 main.log.error( self.name + ": " +
2748 handle + '\033[0m' )
2749 return main.ERROR
2750 return main.TRUE
2751 else:
2752 main.log.error( "Invalid 'role' given to device_role(). " +
2753 "Value was '" + str(role) + "'." )
2754 return main.FALSE
2755 except AssertionError:
2756 main.log.exception( "" )
2757 return None
2758 except TypeError:
2759 main.log.exception( self.name + ": Object not as expected" )
2760 return None
2761 except pexpect.EOF:
2762 main.log.error( self.name + ": EOF exception found" )
2763 main.log.error( self.name + ": " + self.handle.before )
2764 main.cleanup()
2765 main.exit()
2766 except Exception:
2767 main.log.exception( self.name + ": Uncaught exception!" )
2768 main.cleanup()
2769 main.exit()
2770
2771 def clusters( self, jsonFormat=True ):
2772 """
2773 Lists all clusters
2774 Optional argument:
2775 * jsonFormat - boolean indicating if you want output in json
2776 """
2777 try:
2778 cmdStr = "clusters"
2779 if jsonFormat:
2780 cmdStr += " -j"
2781 handle = self.sendline( cmdStr )
2782 assert "Command not found:" not in handle, handle
2783 return handle
2784 except AssertionError:
2785 main.log.exception( "" )
2786 return None
2787 except TypeError:
2788 main.log.exception( self.name + ": Object not as expected" )
2789 return None
2790 except pexpect.EOF:
2791 main.log.error( self.name + ": EOF exception found" )
2792 main.log.error( self.name + ": " + self.handle.before )
2793 main.cleanup()
2794 main.exit()
2795 except Exception:
2796 main.log.exception( self.name + ": Uncaught exception!" )
2797 main.cleanup()
2798 main.exit()
2799
2800 def electionTestLeader( self ):
2801 """
2802 CLI command to get the current leader for the Election test application
2803 NOTE: Requires installation of the onos-app-election feature
2804 Returns: Node IP of the leader if one exists
2805 None if none exists
2806 Main.FALSE on error
2807 """
2808 try:
2809 cmdStr = "election-test-leader"
2810 response = self.sendline( cmdStr )
2811 assert "Command not found:" not in response, response
2812 # Leader
2813 leaderPattern = "The\scurrent\sleader\sfor\sthe\sElection\s" +\
2814 "app\sis\s(?P<node>.+)\."
2815 nodeSearch = re.search( leaderPattern, response )
2816 if nodeSearch:
2817 node = nodeSearch.group( 'node' )
2818 main.log.info( "Election-test-leader on " + str( self.name ) +
2819 " found " + node + " as the leader" )
2820 return node
2821 # no leader
2822 nullPattern = "There\sis\scurrently\sno\sleader\selected\sfor\s" +\
2823 "the\sElection\sapp"
2824 nullSearch = re.search( nullPattern, response )
2825 if nullSearch:
2826 main.log.info( "Election-test-leader found no leader on " +
2827 self.name )
2828 return None
2829 # error
2830 errorPattern = "Command\snot\sfound"
2831 if re.search( errorPattern, response ):
2832 main.log.error( "Election app is not loaded on " + self.name )
2833 # TODO: Should this be main.ERROR?
2834 return main.FALSE
2835 else:
2836 main.log.error( "Error in electionTestLeader on " + self.name +
2837 ": " + "unexpected response" )
2838 main.log.error( repr( response ) )
2839 return main.FALSE
2840 except AssertionError:
2841 main.log.exception( "" )
2842 return None
2843 except TypeError:
2844 main.log.exception( self.name + ": Object not as expected" )
2845 return main.FALSE
2846 except pexpect.EOF:
2847 main.log.error( self.name + ": EOF exception found" )
2848 main.log.error( self.name + ": " + self.handle.before )
2849 main.cleanup()
2850 main.exit()
2851 except Exception:
2852 main.log.exception( self.name + ": Uncaught exception!" )
2853 main.cleanup()
2854 main.exit()
2855
2856 def electionTestRun( self ):
2857 """
2858 CLI command to run for leadership of the Election test application.
2859 NOTE: Requires installation of the onos-app-election feature
2860 Returns: Main.TRUE on success
2861 Main.FALSE on error
2862 """
2863 try:
2864 cmdStr = "election-test-run"
2865 response = self.sendline( cmdStr )
2866 assert "Command not found:" not in response, response
2867 # success
2868 successPattern = "Entering\sleadership\selections\sfor\sthe\s" +\
2869 "Election\sapp."
2870 search = re.search( successPattern, response )
2871 if search:
2872 main.log.info( self.name + " entering leadership elections " +
2873 "for the Election app." )
2874 return main.TRUE
2875 # error
2876 errorPattern = "Command\snot\sfound"
2877 if re.search( errorPattern, response ):
2878 main.log.error( "Election app is not loaded on " + self.name )
2879 return main.FALSE
2880 else:
2881 main.log.error( "Error in electionTestRun on " + self.name +
2882 ": " + "unexpected response" )
2883 main.log.error( repr( response ) )
2884 return main.FALSE
2885 except AssertionError:
2886 main.log.exception( "" )
2887 return None
2888 except TypeError:
2889 main.log.exception( self.name + ": Object not as expected" )
2890 return main.FALSE
2891 except pexpect.EOF:
2892 main.log.error( self.name + ": EOF exception found" )
2893 main.log.error( self.name + ": " + self.handle.before )
2894 main.cleanup()
2895 main.exit()
2896 except Exception:
2897 main.log.exception( self.name + ": Uncaught exception!" )
2898 main.cleanup()
2899 main.exit()
2900
2901 def electionTestWithdraw( self ):
2902 """
2903 * CLI command to withdraw the local node from leadership election for
2904 * the Election test application.
2905 #NOTE: Requires installation of the onos-app-election feature
2906 Returns: Main.TRUE on success
2907 Main.FALSE on error
2908 """
2909 try:
2910 cmdStr = "election-test-withdraw"
2911 response = self.sendline( cmdStr )
2912 assert "Command not found:" not in response, response
2913 # success
2914 successPattern = "Withdrawing\sfrom\sleadership\selections\sfor" +\
2915 "\sthe\sElection\sapp."
2916 if re.search( successPattern, response ):
2917 main.log.info( self.name + " withdrawing from leadership " +
2918 "elections for the Election app." )
2919 return main.TRUE
2920 # error
2921 errorPattern = "Command\snot\sfound"
2922 if re.search( errorPattern, response ):
2923 main.log.error( "Election app is not loaded on " + self.name )
2924 return main.FALSE
2925 else:
2926 main.log.error( "Error in electionTestWithdraw on " +
2927 self.name + ": " + "unexpected response" )
2928 main.log.error( repr( response ) )
2929 return main.FALSE
2930 except AssertionError:
2931 main.log.exception( "" )
2932 return None
2933 except TypeError:
2934 main.log.exception( self.name + ": Object not as expected" )
2935 return main.FALSE
2936 except pexpect.EOF:
2937 main.log.error( self.name + ": EOF exception found" )
2938 main.log.error( self.name + ": " + self.handle.before )
2939 main.cleanup()
2940 main.exit()
2941 except Exception:
2942 main.log.exception( self.name + ": Uncaught exception!" )
2943 main.cleanup()
2944 main.exit()
2945
2946 def getDevicePortsEnabledCount( self, dpid ):
2947 """
2948 Get the count of all enabled ports on a particular device/switch
2949 """
2950 try:
2951 dpid = str( dpid )
2952 cmdStr = "onos:ports -e " + dpid + " | wc -l"
2953 output = self.sendline( cmdStr )
2954 assert "Command not found:" not in output, output
2955 if re.search( "No such device", output ):
2956 main.log.error( "Error in getting ports" )
2957 return ( output, "Error" )
2958 else:
2959 return output
2960 except AssertionError:
2961 main.log.exception( "" )
2962 return None
2963 except TypeError:
2964 main.log.exception( self.name + ": Object not as expected" )
2965 return ( output, "Error" )
2966 except pexpect.EOF:
2967 main.log.error( self.name + ": EOF exception found" )
2968 main.log.error( self.name + ": " + self.handle.before )
2969 main.cleanup()
2970 main.exit()
2971 except Exception:
2972 main.log.exception( self.name + ": Uncaught exception!" )
2973 main.cleanup()
2974 main.exit()
2975
2976 def getDeviceLinksActiveCount( self, dpid ):
2977 """
2978 Get the count of all enabled ports on a particular device/switch
2979 """
2980 try:
2981 dpid = str( dpid )
2982 cmdStr = "onos:links " + dpid + " | grep ACTIVE | wc -l"
2983 output = self.sendline( cmdStr )
2984 assert "Command not found:" not in output, output
2985 if re.search( "No such device", output ):
2986 main.log.error( "Error in getting ports " )
2987 return ( output, "Error " )
2988 else:
2989 return output
2990 except AssertionError:
2991 main.log.exception( "" )
2992 return None
2993 except TypeError:
2994 main.log.exception( self.name + ": Object not as expected" )
2995 return ( output, "Error " )
2996 except pexpect.EOF:
2997 main.log.error( self.name + ": EOF exception found" )
2998 main.log.error( self.name + ": " + self.handle.before )
2999 main.cleanup()
3000 main.exit()
3001 except Exception:
3002 main.log.exception( self.name + ": Uncaught exception!" )
3003 main.cleanup()
3004 main.exit()
3005
3006 def getAllIntentIds( self ):
3007 """
3008 Return a list of all Intent IDs
3009 """
3010 try:
3011 cmdStr = "onos:intents | grep id="
3012 output = self.sendline( cmdStr )
3013 assert "Command not found:" not in output, output
3014 if re.search( "Error", output ):
3015 main.log.error( "Error in getting ports" )
3016 return ( output, "Error" )
3017 else:
3018 return output
3019 except AssertionError:
3020 main.log.exception( "" )
3021 return None
3022 except TypeError:
3023 main.log.exception( self.name + ": Object not as expected" )
3024 return ( output, "Error" )
3025 except pexpect.EOF:
3026 main.log.error( self.name + ": EOF exception found" )
3027 main.log.error( self.name + ": " + self.handle.before )
3028 main.cleanup()
3029 main.exit()
3030 except Exception:
3031 main.log.exception( self.name + ": Uncaught exception!" )
3032 main.cleanup()
3033 main.exit()
3034
3035 def intentSummary( self ):
3036 """
3037 Returns a dictionary containing the current intent states and the count
3038 """
3039 try:
3040 intents = self.intents( )
3041 states = []
3042 for intent in json.loads( intents ):
3043 states.append( intent.get( 'state', None ) )
3044 out = [ ( i, states.count( i ) ) for i in set( states ) ]
3045 main.log.info( dict( out ) )
3046 return dict( out )
3047 except ( TypeError, ValueError ):
3048 main.log.exception( "{}: Object not as expected: {!r}".format( self.name, intents ) )
3049 return None
3050 except pexpect.EOF:
3051 main.log.error( self.name + ": EOF exception found" )
3052 main.log.error( self.name + ": " + self.handle.before )
3053 main.cleanup()
3054 main.exit()
3055 except Exception:
3056 main.log.exception( self.name + ": Uncaught exception!" )
3057 main.cleanup()
3058 main.exit()
3059
3060 def leaders( self, jsonFormat=True ):
3061 """
3062 Returns the output of the leaders command.
3063 Optional argument:
3064 * jsonFormat - boolean indicating if you want output in json
3065 """
3066 try:
3067 cmdStr = "onos:leaders"
3068 if jsonFormat:
3069 cmdStr += " -j"
3070 output = self.sendline( cmdStr )
3071 assert "Command not found:" not in output, output
3072 return output
3073 except AssertionError:
3074 main.log.exception( "" )
3075 return None
3076 except TypeError:
3077 main.log.exception( self.name + ": Object not as expected" )
3078 return None
3079 except pexpect.EOF:
3080 main.log.error( self.name + ": EOF exception found" )
3081 main.log.error( self.name + ": " + self.handle.before )
3082 main.cleanup()
3083 main.exit()
3084 except Exception:
3085 main.log.exception( self.name + ": Uncaught exception!" )
3086 main.cleanup()
3087 main.exit()
3088
3089 def leaderCandidates( self, jsonFormat=True ):
3090 """
3091 Returns the output of the leaders -c command.
3092 Optional argument:
3093 * jsonFormat - boolean indicating if you want output in json
3094 """
3095 try:
3096 cmdStr = "onos:leaders -c"
3097 if jsonFormat:
3098 cmdStr += " -j"
3099 output = self.sendline( cmdStr )
3100 assert "Command not found:" not in output, output
3101 return output
3102 except AssertionError:
3103 main.log.exception( "" )
3104 return None
3105 except TypeError:
3106 main.log.exception( self.name + ": Object not as expected" )
3107 return None
3108 except pexpect.EOF:
3109 main.log.error( self.name + ": EOF exception found" )
3110 main.log.error( self.name + ": " + self.handle.before )
3111 main.cleanup()
3112 main.exit()
3113 except Exception:
3114 main.log.exception( self.name + ": Uncaught exception!" )
3115 main.cleanup()
3116 main.exit()
3117
3118 def specificLeaderCandidate( self, topic ):
3119 """
3120 Returns a list in format [leader,candidate1,candidate2,...] for a given
3121 topic parameter and an empty list if the topic doesn't exist
3122 If no leader is elected leader in the returned list will be "none"
3123 Returns None if there is a type error processing the json object
3124 """
3125 try:
3126 cmdStr = "onos:leaders -j"
3127 rawOutput = self.sendline( cmdStr )
3128 assert "Command not found:" not in rawOutput, rawOutput
3129 output = json.loads( rawOutput )
3130 results = []
3131 for dict in output:
3132 if dict["topic"] == topic:
3133 leader = dict["leader"]
3134 candidates = re.split( ", ", dict["candidates"][1:-1] )
3135 results.append( leader )
3136 results.extend( candidates )
3137 return results
3138 except AssertionError:
3139 main.log.exception( "" )
3140 return None
3141 except ( TypeError, ValueError ):
3142 main.log.exception( "{}: Object not as expected: {!r}".format( self.name, rawOutput ) )
3143 return None
3144 except pexpect.EOF:
3145 main.log.error( self.name + ": EOF exception found" )
3146 main.log.error( self.name + ": " + self.handle.before )
3147 main.cleanup()
3148 main.exit()
3149 except Exception:
3150 main.log.exception( self.name + ": Uncaught exception!" )
3151 main.cleanup()
3152 main.exit()
3153
3154 def pendingMap( self, jsonFormat=True ):
3155 """
3156 Returns the output of the intent Pending map.
3157 """
3158 try:
3159 cmdStr = "onos:intents -p"
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 partitions( self, jsonFormat=True ):
3182 """
3183 Returns the output of the raft partitions command for ONOS.
3184 """
3185 # Sample JSON
3186 # {
3187 # "leader": "tcp://10.128.30.11:7238",
3188 # "members": [
3189 # "tcp://10.128.30.11:7238",
3190 # "tcp://10.128.30.17:7238",
3191 # "tcp://10.128.30.13:7238",
3192 # ],
3193 # "name": "p1",
3194 # "term": 3
3195 # },
3196 try:
3197 cmdStr = "onos:partitions"
3198 if jsonFormat:
3199 cmdStr += " -j"
3200 output = self.sendline( cmdStr )
3201 assert "Command not found:" not in output, output
3202 return output
3203 except AssertionError:
3204 main.log.exception( "" )
3205 return None
3206 except TypeError:
3207 main.log.exception( self.name + ": Object not as expected" )
3208 return None
3209 except pexpect.EOF:
3210 main.log.error( self.name + ": EOF exception found" )
3211 main.log.error( self.name + ": " + self.handle.before )
3212 main.cleanup()
3213 main.exit()
3214 except Exception:
3215 main.log.exception( self.name + ": Uncaught exception!" )
3216 main.cleanup()
3217 main.exit()
3218
3219 def apps( self, jsonFormat=True ):
3220 """
3221 Returns the output of the apps command for ONOS. This command lists
3222 information about installed ONOS applications
3223 """
3224 # Sample JSON object
3225 # [{"name":"org.onosproject.openflow","id":0,"version":"1.2.0",
3226 # "description":"ONOS OpenFlow protocol southbound providers",
3227 # "origin":"ON.Lab","permissions":"[]","featuresRepo":"",
3228 # "features":"[onos-openflow]","state":"ACTIVE"}]
3229 try:
3230 cmdStr = "onos:apps"
3231 if jsonFormat:
3232 cmdStr += " -j"
3233 output = self.sendline( cmdStr )
3234 assert "Command not found:" not in output, output
3235 assert "Error executing command" not in output, output
3236 return output
3237 # FIXME: look at specific exceptions/Errors
3238 except AssertionError:
3239 main.log.exception( "Error in processing onos:app command." )
3240 return None
3241 except TypeError:
3242 main.log.exception( self.name + ": Object not as expected" )
3243 return None
3244 except pexpect.EOF:
3245 main.log.error( self.name + ": EOF exception found" )
3246 main.log.error( self.name + ": " + self.handle.before )
3247 main.cleanup()
3248 main.exit()
3249 except Exception:
3250 main.log.exception( self.name + ": Uncaught exception!" )
3251 main.cleanup()
3252 main.exit()
3253
3254 def appStatus( self, appName ):
3255 """
3256 Uses the onos:apps cli command to return the status of an application.
3257 Returns:
3258 "ACTIVE" - If app is installed and activated
3259 "INSTALLED" - If app is installed and deactivated
3260 "UNINSTALLED" - If app is not installed
3261 None - on error
3262 """
3263 try:
3264 if not isinstance( appName, types.StringType ):
3265 main.log.error( self.name + ".appStatus(): appName must be" +
3266 " a string" )
3267 return None
3268 output = self.apps( jsonFormat=True )
3269 appsJson = json.loads( output )
3270 state = None
3271 for app in appsJson:
3272 if appName == app.get('name'):
3273 state = app.get('state')
3274 break
3275 if state == "ACTIVE" or state == "INSTALLED":
3276 return state
3277 elif state is None:
3278 return "UNINSTALLED"
3279 elif state:
3280 main.log.error( "Unexpected state from 'onos:apps': " +
3281 str( state ) )
3282 return state
3283 except ( TypeError, ValueError ):
3284 main.log.exception( "{}: Object not as expected: {!r}".format( self.name, output ) )
3285 main.stop()
3286 return None
3287 except pexpect.EOF:
3288 main.log.error( self.name + ": EOF exception found" )
3289 main.log.error( self.name + ": " + self.handle.before )
3290 main.cleanup()
3291 main.exit()
3292 except Exception:
3293 main.log.exception( self.name + ": Uncaught exception!" )
3294 main.cleanup()
3295 main.exit()
3296
3297 def app( self, appName, option ):
3298 """
3299 Interacts with the app command for ONOS. This command manages
3300 application inventory.
3301 """
3302 try:
3303 # Validate argument types
3304 valid = True
3305 if not isinstance( appName, types.StringType ):
3306 main.log.error( self.name + ".app(): appName must be a " +
3307 "string" )
3308 valid = False
3309 if not isinstance( option, types.StringType ):
3310 main.log.error( self.name + ".app(): option must be a string" )
3311 valid = False
3312 if not valid:
3313 return main.FALSE
3314 # Validate Option
3315 option = option.lower()
3316 # NOTE: Install may become a valid option
3317 if option == "activate":
3318 pass
3319 elif option == "deactivate":
3320 pass
3321 elif option == "uninstall":
3322 pass
3323 else:
3324 # Invalid option
3325 main.log.error( "The ONOS app command argument only takes " +
3326 "the values: (activate|deactivate|uninstall)" +
3327 "; was given '" + option + "'")
3328 return main.FALSE
3329 cmdStr = "onos:app " + option + " " + appName
3330 output = self.sendline( cmdStr )
3331 if "Error executing command" in output:
3332 main.log.error( "Error in processing onos:app command: " +
3333 str( output ) )
3334 return main.FALSE
3335 elif "No such application" in output:
3336 main.log.error( "The application '" + appName +
3337 "' is not installed in ONOS" )
3338 return main.FALSE
3339 elif "Command not found:" in output:
3340 main.log.error( "Error in processing onos:app command: " +
3341 str( output ) )
3342 return main.FALSE
3343 elif "Unsupported command:" in output:
3344 main.log.error( "Incorrect command given to 'app': " +
3345 str( output ) )
3346 # NOTE: we may need to add more checks here
3347 # else: Command was successful
3348 # main.log.debug( "app response: " + repr( output ) )
3349 return main.TRUE
3350 except TypeError:
3351 main.log.exception( self.name + ": Object not as expected" )
3352 return main.ERROR
3353 except pexpect.EOF:
3354 main.log.error( self.name + ": EOF exception found" )
3355 main.log.error( self.name + ": " + self.handle.before )
3356 main.cleanup()
3357 main.exit()
3358 except Exception:
3359 main.log.exception( self.name + ": Uncaught exception!" )
3360 main.cleanup()
3361 main.exit()
3362
3363 def activateApp( self, appName, check=True ):
3364 """
3365 Activate an app that is already installed in ONOS
3366 appName is the hierarchical app name, not the feature name
3367 If check is True, method will check the status of the app after the
3368 command is issued
3369 Returns main.TRUE if the command was successfully sent
3370 main.FALSE if the cli responded with an error or given
3371 incorrect input
3372 """
3373 try:
3374 if not isinstance( appName, types.StringType ):
3375 main.log.error( self.name + ".activateApp(): appName must be" +
3376 " a string" )
3377 return main.FALSE
3378 status = self.appStatus( appName )
3379 if status == "INSTALLED":
3380 response = self.app( appName, "activate" )
3381 if check and response == main.TRUE:
3382 for i in range(10): # try 10 times then give up
3383 status = self.appStatus( appName )
3384 if status == "ACTIVE":
3385 return main.TRUE
3386 else:
3387 main.log.debug( "The state of application " +
3388 appName + " is " + status )
3389 time.sleep( 1 )
3390 return main.FALSE
3391 else: # not 'check' or command didn't succeed
3392 return response
3393 elif status == "ACTIVE":
3394 return main.TRUE
3395 elif status == "UNINSTALLED":
3396 main.log.error( self.name + ": Tried to activate the " +
3397 "application '" + appName + "' which is not " +
3398 "installed." )
3399 else:
3400 main.log.error( "Unexpected return value from appStatus: " +
3401 str( status ) )
3402 return main.ERROR
3403 except TypeError:
3404 main.log.exception( self.name + ": Object not as expected" )
3405 return main.ERROR
3406 except pexpect.EOF:
3407 main.log.error( self.name + ": EOF exception found" )
3408 main.log.error( self.name + ": " + self.handle.before )
3409 main.cleanup()
3410 main.exit()
3411 except Exception:
3412 main.log.exception( self.name + ": Uncaught exception!" )
3413 main.cleanup()
3414 main.exit()
3415
3416 def deactivateApp( self, appName, check=True ):
3417 """
3418 Deactivate an app that is already activated in ONOS
3419 appName is the hierarchical app name, not the feature name
3420 If check is True, method will check the status of the app after the
3421 command is issued
3422 Returns main.TRUE if the command was successfully sent
3423 main.FALSE if the cli responded with an error or given
3424 incorrect input
3425 """
3426 try:
3427 if not isinstance( appName, types.StringType ):
3428 main.log.error( self.name + ".deactivateApp(): appName must " +
3429 "be a string" )
3430 return main.FALSE
3431 status = self.appStatus( appName )
3432 if status == "INSTALLED":
3433 return main.TRUE
3434 elif status == "ACTIVE":
3435 response = self.app( appName, "deactivate" )
3436 if check and response == main.TRUE:
3437 for i in range(10): # try 10 times then give up
3438 status = self.appStatus( appName )
3439 if status == "INSTALLED":
3440 return main.TRUE
3441 else:
3442 time.sleep( 1 )
3443 return main.FALSE
3444 else: # not check or command didn't succeed
3445 return response
3446 elif status == "UNINSTALLED":
3447 main.log.warn( self.name + ": Tried to deactivate the " +
3448 "application '" + appName + "' which is not " +
3449 "installed." )
3450 return main.TRUE
3451 else:
3452 main.log.error( "Unexpected return value from appStatus: " +
3453 str( status ) )
3454 return main.ERROR
3455 except TypeError:
3456 main.log.exception( self.name + ": Object not as expected" )
3457 return main.ERROR
3458 except pexpect.EOF:
3459 main.log.error( self.name + ": EOF exception found" )
3460 main.log.error( self.name + ": " + self.handle.before )
3461 main.cleanup()
3462 main.exit()
3463 except Exception:
3464 main.log.exception( self.name + ": Uncaught exception!" )
3465 main.cleanup()
3466 main.exit()
3467
3468 def uninstallApp( self, appName, check=True ):
3469 """
3470 Uninstall an app that is already installed in ONOS
3471 appName is the hierarchical app name, not the feature name
3472 If check is True, method will check the status of the app after the
3473 command is issued
3474 Returns main.TRUE if the command was successfully sent
3475 main.FALSE if the cli responded with an error or given
3476 incorrect input
3477 """
3478 # TODO: check with Thomas about the state machine for apps
3479 try:
3480 if not isinstance( appName, types.StringType ):
3481 main.log.error( self.name + ".uninstallApp(): appName must " +
3482 "be a string" )
3483 return main.FALSE
3484 status = self.appStatus( appName )
3485 if status == "INSTALLED":
3486 response = self.app( appName, "uninstall" )
3487 if check and response == main.TRUE:
3488 for i in range(10): # try 10 times then give up
3489 status = self.appStatus( appName )
3490 if status == "UNINSTALLED":
3491 return main.TRUE
3492 else:
3493 time.sleep( 1 )
3494 return main.FALSE
3495 else: # not check or command didn't succeed
3496 return response
3497 elif status == "ACTIVE":
3498 main.log.warn( self.name + ": Tried to uninstall the " +
3499 "application '" + appName + "' which is " +
3500 "currently active." )
3501 response = self.app( appName, "uninstall" )
3502 if check and response == main.TRUE:
3503 for i in range(10): # try 10 times then give up
3504 status = self.appStatus( appName )
3505 if status == "UNINSTALLED":
3506 return main.TRUE
3507 else:
3508 time.sleep( 1 )
3509 return main.FALSE
3510 else: # not check or command didn't succeed
3511 return response
3512 elif status == "UNINSTALLED":
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 appIDs( self, jsonFormat=True ):
3532 """
3533 Show the mappings between app id and app names given by the 'app-ids'
3534 cli command
3535 """
3536 try:
3537 cmdStr = "app-ids"
3538 if jsonFormat:
3539 cmdStr += " -j"
3540 output = self.sendline( cmdStr )
3541 assert "Command not found:" not in output, output
3542 assert "Error executing command" not in output, output
3543 return output
3544 except AssertionError:
3545 main.log.exception( "Error in processing onos:app-ids command." )
3546 return None
3547 except TypeError:
3548 main.log.exception( self.name + ": Object not as expected" )
3549 return None
3550 except pexpect.EOF:
3551 main.log.error( self.name + ": EOF exception found" )
3552 main.log.error( self.name + ": " + self.handle.before )
3553 main.cleanup()
3554 main.exit()
3555 except Exception:
3556 main.log.exception( self.name + ": Uncaught exception!" )
3557 main.cleanup()
3558 main.exit()
3559
3560 def appToIDCheck( self ):
3561 """
3562 This method will check that each application's ID listed in 'apps' is
3563 the same as the ID listed in 'app-ids'. The check will also check that
3564 there are no duplicate IDs issued. Note that an app ID should be
3565 a globaly unique numerical identifier for app/app-like features. Once
3566 an ID is registered, the ID is never freed up so that if an app is
3567 reinstalled it will have the same ID.
3568
3569 Returns: main.TRUE if the check passes and
3570 main.FALSE if the check fails or
3571 main.ERROR if there is some error in processing the test
3572 """
3573 try:
3574 bail = False
3575 rawJson = self.appIDs( jsonFormat=True )
3576 if rawJson:
3577 ids = json.loads( rawJson )
3578 else:
3579 main.log.error( "app-ids returned nothing:" + repr( rawJson ) )
3580 bail = True
3581 rawJson = self.apps( jsonFormat=True )
3582 if rawJson:
3583 apps = json.loads( rawJson )
3584 else:
3585 main.log.error( "apps returned nothing:" + repr( rawJson ) )
3586 bail = True
3587 if bail:
3588 return main.FALSE
3589 result = main.TRUE
3590 for app in apps:
3591 appID = app.get( 'id' )
3592 if appID is None:
3593 main.log.error( "Error parsing app: " + str( app ) )
3594 result = main.FALSE
3595 appName = app.get( 'name' )
3596 if appName is None:
3597 main.log.error( "Error parsing app: " + str( app ) )
3598 result = main.FALSE
3599 # get the entry in ids that has the same appID
3600 current = filter( lambda item: item[ 'id' ] == appID, ids )
3601 # main.log.debug( "Comparing " + str( app ) + " to " +
3602 # str( current ) )
3603 if not current: # if ids doesn't have this id
3604 result = main.FALSE
3605 main.log.error( "'app-ids' does not have the ID for " +
3606 str( appName ) + " that apps does." )
3607 elif len( current ) > 1:
3608 # there is more than one app with this ID
3609 result = main.FALSE
3610 # We will log this later in the method
3611 elif not current[0][ 'name' ] == appName:
3612 currentName = current[0][ 'name' ]
3613 result = main.FALSE
3614 main.log.error( "'app-ids' has " + str( currentName ) +
3615 " registered under id:" + str( appID ) +
3616 " but 'apps' has " + str( appName ) )
3617 else:
3618 pass # id and name match!
3619 # now make sure that app-ids has no duplicates
3620 idsList = []
3621 namesList = []
3622 for item in ids:
3623 idsList.append( item[ 'id' ] )
3624 namesList.append( item[ 'name' ] )
3625 if len( idsList ) != len( set( idsList ) ) or\
3626 len( namesList ) != len( set( namesList ) ):
3627 main.log.error( "'app-ids' has some duplicate entries: \n"
3628 + json.dumps( ids,
3629 sort_keys=True,
3630 indent=4,
3631 separators=( ',', ': ' ) ) )
3632 result = main.FALSE
3633 return result
3634 except ( TypeError, ValueError ):
3635 main.log.exception( "{}: Object not as expected: {!r}".format( self.name, rawJson ) )
3636 return main.ERROR
3637 except pexpect.EOF:
3638 main.log.error( self.name + ": EOF exception found" )
3639 main.log.error( self.name + ": " + self.handle.before )
3640 main.cleanup()
3641 main.exit()
3642 except Exception:
3643 main.log.exception( self.name + ": Uncaught exception!" )
3644 main.cleanup()
3645 main.exit()
3646
3647 def getCfg( self, component=None, propName=None, short=False,
3648 jsonFormat=True ):
3649 """
3650 Get configuration settings from onos cli
3651 Optional arguments:
3652 component - Optionally only list configurations for a specific
3653 component. If None, all components with configurations
3654 are displayed. Case Sensitive string.
3655 propName - If component is specified, propName option will show
3656 only this specific configuration from that component.
3657 Case Sensitive string.
3658 jsonFormat - Returns output as json. Note that this will override
3659 the short option
3660 short - Short, less verbose, version of configurations.
3661 This is overridden by the json option
3662 returns:
3663 Output from cli as a string or None on error
3664 """
3665 try:
3666 baseStr = "cfg"
3667 cmdStr = " get"
3668 componentStr = ""
3669 if component:
3670 componentStr += " " + component
3671 if propName:
3672 componentStr += " " + propName
3673 if jsonFormat:
3674 baseStr += " -j"
3675 elif short:
3676 baseStr += " -s"
3677 output = self.sendline( baseStr + cmdStr + componentStr )
3678 assert "Command not found:" not in output, output
3679 assert "Error executing command" not in output, output
3680 return output
3681 except AssertionError:
3682 main.log.exception( "Error in processing 'cfg get' command." )
3683 return None
3684 except TypeError:
3685 main.log.exception( self.name + ": Object not as expected" )
3686 return None
3687 except pexpect.EOF:
3688 main.log.error( self.name + ": EOF exception found" )
3689 main.log.error( self.name + ": " + self.handle.before )
3690 main.cleanup()
3691 main.exit()
3692 except Exception:
3693 main.log.exception( self.name + ": Uncaught exception!" )
3694 main.cleanup()
3695 main.exit()
3696
3697 def setCfg( self, component, propName, value=None, check=True ):
3698 """
3699 Set/Unset configuration settings from ONOS cli
3700 Required arguments:
3701 component - The case sensitive name of the component whose
3702 property is to be set
3703 propName - The case sensitive name of the property to be set/unset
3704 Optional arguments:
3705 value - The value to set the property to. If None, will unset the
3706 property and revert it to it's default value(if applicable)
3707 check - Boolean, Check whether the option was successfully set this
3708 only applies when a value is given.
3709 returns:
3710 main.TRUE on success or main.FALSE on failure. If check is False,
3711 will return main.TRUE unless there is an error
3712 """
3713 try:
3714 baseStr = "cfg"
3715 cmdStr = " set " + str( component ) + " " + str( propName )
3716 if value is not None:
3717 cmdStr += " " + str( value )
3718 output = self.sendline( baseStr + cmdStr )
3719 assert "Command not found:" not in output, output
3720 assert "Error executing command" not in output, output
3721 if value and check:
3722 results = self.getCfg( component=str( component ),
3723 propName=str( propName ),
3724 jsonFormat=True )
3725 # Check if current value is what we just set
3726 try:
3727 jsonOutput = json.loads( results )
3728 current = jsonOutput[ 'value' ]
3729 except ( TypeError, ValueError ):
3730 main.log.exception( "Error parsing cfg output" )
3731 main.log.error( "output:" + repr( results ) )
3732 return main.FALSE
3733 if current == str( value ):
3734 return main.TRUE
3735 return main.FALSE
3736 return main.TRUE
3737 except AssertionError:
3738 main.log.exception( "Error in processing 'cfg set' command." )
3739 return main.FALSE
3740 except ( TypeError, ValueError ):
3741 main.log.exception( "{}: Object not as expected: {!r}".format( self.name, results ) )
3742 return main.FALSE
3743 except pexpect.EOF:
3744 main.log.error( self.name + ": EOF exception found" )
3745 main.log.error( self.name + ": " + self.handle.before )
3746 main.cleanup()
3747 main.exit()
3748 except Exception:
3749 main.log.exception( self.name + ": Uncaught exception!" )
3750 main.cleanup()
3751 main.exit()
3752
3753 def setTestAdd( self, setName, values ):
3754 """
3755 CLI command to add elements to a distributed set.
3756 Arguments:
3757 setName - The name of the set to add to.
3758 values - The value(s) to add to the set, space seperated.
3759 Example usages:
3760 setTestAdd( "set1", "a b c" )
3761 setTestAdd( "set2", "1" )
3762 returns:
3763 main.TRUE on success OR
3764 main.FALSE if elements were already in the set OR
3765 main.ERROR on error
3766 """
3767 try:
3768 cmdStr = "set-test-add " + str( setName ) + " " + str( values )
3769 output = self.sendline( cmdStr )
3770 assert "Command not found:" not in output, output
3771 try:
3772 # TODO: Maybe make this less hardcoded
3773 # ConsistentMap Exceptions
3774 assert "org.onosproject.store.service" not in output
3775 # Node not leader
3776 assert "java.lang.IllegalStateException" not in output
3777 except AssertionError:
3778 main.log.error( "Error in processing '" + cmdStr + "' " +
3779 "command: " + str( output ) )
3780 retryTime = 30 # Conservative time, given by Madan
3781 main.log.info( "Waiting " + str( retryTime ) +
3782 "seconds before retrying." )
3783 time.sleep( retryTime ) # Due to change in mastership
3784 output = self.sendline( cmdStr )
3785 assert "Error executing command" not in output
3786 positiveMatch = "\[(.*)\] was added to the set " + str( setName )
3787 negativeMatch = "\[(.*)\] was already in set " + str( setName )
3788 main.log.info( self.name + ": " + output )
3789 if re.search( positiveMatch, output):
3790 return main.TRUE
3791 elif re.search( negativeMatch, output):
3792 return main.FALSE
3793 else:
3794 main.log.error( self.name + ": setTestAdd did not" +
3795 " match expected output" )
3796 main.log.debug( self.name + " actual: " + repr( output ) )
3797 return main.ERROR
3798 except AssertionError:
3799 main.log.exception( "Error in processing '" + cmdStr + "' command. " )
3800 return main.ERROR
3801 except TypeError:
3802 main.log.exception( self.name + ": Object not as expected" )
3803 return main.ERROR
3804 except pexpect.EOF:
3805 main.log.error( self.name + ": EOF exception found" )
3806 main.log.error( self.name + ": " + self.handle.before )
3807 main.cleanup()
3808 main.exit()
3809 except Exception:
3810 main.log.exception( self.name + ": Uncaught exception!" )
3811 main.cleanup()
3812 main.exit()
3813
3814 def setTestRemove( self, setName, values, clear=False, retain=False ):
3815 """
3816 CLI command to remove elements from a distributed set.
3817 Required arguments:
3818 setName - The name of the set to remove from.
3819 values - The value(s) to remove from the set, space seperated.
3820 Optional arguments:
3821 clear - Clear all elements from the set
3822 retain - Retain only the given values. (intersection of the
3823 original set and the given set)
3824 returns:
3825 main.TRUE on success OR
3826 main.FALSE if the set was not changed OR
3827 main.ERROR on error
3828 """
3829 try:
3830 cmdStr = "set-test-remove "
3831 if clear:
3832 cmdStr += "-c " + str( setName )
3833 elif retain:
3834 cmdStr += "-r " + str( setName ) + " " + str( values )
3835 else:
3836 cmdStr += str( setName ) + " " + str( values )
3837 output = self.sendline( cmdStr )
3838 try:
3839 # TODO: Maybe make this less hardcoded
3840 # ConsistentMap Exceptions
3841 assert "org.onosproject.store.service" not in output
3842 # Node not leader
3843 assert "java.lang.IllegalStateException" not in output
3844 except AssertionError:
3845 main.log.error( "Error in processing '" + cmdStr + "' " +
3846 "command: " + str( output ) )
3847 retryTime = 30 # Conservative time, given by Madan
3848 main.log.info( "Waiting " + str( retryTime ) +
3849 "seconds before retrying." )
3850 time.sleep( retryTime ) # Due to change in mastership
3851 output = self.sendline( cmdStr )
3852 assert "Command not found:" not in output, output
3853 assert "Error executing command" not in output, output
3854 main.log.info( self.name + ": " + output )
3855 if clear:
3856 pattern = "Set " + str( setName ) + " cleared"
3857 if re.search( pattern, output ):
3858 return main.TRUE
3859 elif retain:
3860 positivePattern = str( setName ) + " was pruned to contain " +\
3861 "only elements of set \[(.*)\]"
3862 negativePattern = str( setName ) + " was not changed by " +\
3863 "retaining only elements of the set " +\
3864 "\[(.*)\]"
3865 if re.search( positivePattern, output ):
3866 return main.TRUE
3867 elif re.search( negativePattern, output ):
3868 return main.FALSE
3869 else:
3870 positivePattern = "\[(.*)\] was removed from the set " +\
3871 str( setName )
3872 if ( len( values.split() ) == 1 ):
3873 negativePattern = "\[(.*)\] was not in set " +\
3874 str( setName )
3875 else:
3876 negativePattern = "No element of \[(.*)\] was in set " +\
3877 str( setName )
3878 if re.search( positivePattern, output ):
3879 return main.TRUE
3880 elif re.search( negativePattern, output ):
3881 return main.FALSE
3882 main.log.error( self.name + ": setTestRemove did not" +
3883 " match expected output" )
3884 main.log.debug( self.name + " expected: " + pattern )
3885 main.log.debug( self.name + " actual: " + repr( output ) )
3886 return main.ERROR
3887 except AssertionError:
3888 main.log.exception( "Error in processing '" + cmdStr + "' commandr. " )
3889 return main.ERROR
3890 except TypeError:
3891 main.log.exception( self.name + ": Object not as expected" )
3892 return main.ERROR
3893 except pexpect.EOF:
3894 main.log.error( self.name + ": EOF exception found" )
3895 main.log.error( self.name + ": " + self.handle.before )
3896 main.cleanup()
3897 main.exit()
3898 except Exception:
3899 main.log.exception( self.name + ": Uncaught exception!" )
3900 main.cleanup()
3901 main.exit()
3902
3903 def setTestGet( self, setName, values="" ):
3904 """
3905 CLI command to get the elements in a distributed set.
3906 Required arguments:
3907 setName - The name of the set to remove from.
3908 Optional arguments:
3909 values - The value(s) to check if in the set, space seperated.
3910 returns:
3911 main.ERROR on error OR
3912 A list of elements in the set if no optional arguments are
3913 supplied OR
3914 A tuple containing the list then:
3915 main.FALSE if the given values are not in the set OR
3916 main.TRUE if the given values are in the set OR
3917 """
3918 try:
3919 values = str( values ).strip()
3920 setName = str( setName ).strip()
3921 length = len( values.split() )
3922 containsCheck = None
3923 # Patterns to match
3924 setPattern = "\[(.*)\]"
3925 pattern = "Items in set " + setName + ":\n" + setPattern
3926 containsTrue = "Set " + setName + " contains the value " + values
3927 containsFalse = "Set " + setName + " did not contain the value " +\
3928 values
3929 containsAllTrue = "Set " + setName + " contains the the subset " +\
3930 setPattern
3931 containsAllFalse = "Set " + setName + " did not contain the the" +\
3932 " subset " + setPattern
3933
3934 cmdStr = "set-test-get "
3935 cmdStr += setName + " " + values
3936 output = self.sendline( cmdStr )
3937 try:
3938 # TODO: Maybe make this less hardcoded
3939 # ConsistentMap Exceptions
3940 assert "org.onosproject.store.service" not in output
3941 # Node not leader
3942 assert "java.lang.IllegalStateException" not in output
3943 except AssertionError:
3944 main.log.error( "Error in processing '" + cmdStr + "' " +
3945 "command: " + str( output ) )
3946 retryTime = 30 # Conservative time, given by Madan
3947 main.log.info( "Waiting " + str( retryTime ) +
3948 "seconds before retrying." )
3949 time.sleep( retryTime ) # Due to change in mastership
3950 output = self.sendline( cmdStr )
3951 assert "Command not found:" not in output, output
3952 assert "Error executing command" not in output, output
3953 main.log.info( self.name + ": " + output )
3954
3955 if length == 0:
3956 match = re.search( pattern, output )
3957 else: # if given values
3958 if length == 1: # Contains output
3959 patternTrue = pattern + "\n" + containsTrue
3960 patternFalse = pattern + "\n" + containsFalse
3961 else: # ContainsAll output
3962 patternTrue = pattern + "\n" + containsAllTrue
3963 patternFalse = pattern + "\n" + containsAllFalse
3964 matchTrue = re.search( patternTrue, output )
3965 matchFalse = re.search( patternFalse, output )
3966 if matchTrue:
3967 containsCheck = main.TRUE
3968 match = matchTrue
3969 elif matchFalse:
3970 containsCheck = main.FALSE
3971 match = matchFalse
3972 else:
3973 main.log.error( self.name + " setTestGet did not match " +\
3974 "expected output" )
3975 main.log.debug( self.name + " expected: " + pattern )
3976 main.log.debug( self.name + " actual: " + repr( output ) )
3977 match = None
3978 if match:
3979 setMatch = match.group( 1 )
3980 if setMatch == '':
3981 setList = []
3982 else:
3983 setList = setMatch.split( ", " )
3984 if length > 0:
3985 return ( setList, containsCheck )
3986 else:
3987 return setList
3988 else: # no match
3989 main.log.error( self.name + ": setTestGet did not" +
3990 " match expected output" )
3991 main.log.debug( self.name + " expected: " + pattern )
3992 main.log.debug( self.name + " actual: " + repr( output ) )
3993 return main.ERROR
3994 except AssertionError:
3995 main.log.exception( "Error in processing '" + cmdStr + "' command." )
3996 return main.ERROR
3997 except TypeError:
3998 main.log.exception( self.name + ": Object not as expected" )
3999 return main.ERROR
4000 except pexpect.EOF:
4001 main.log.error( self.name + ": EOF exception found" )
4002 main.log.error( self.name + ": " + self.handle.before )
4003 main.cleanup()
4004 main.exit()
4005 except Exception:
4006 main.log.exception( self.name + ": Uncaught exception!" )
4007 main.cleanup()
4008 main.exit()
4009
4010 def setTestSize( self, setName ):
4011 """
4012 CLI command to get the elements in a distributed set.
4013 Required arguments:
4014 setName - The name of the set to remove from.
4015 returns:
4016 The integer value of the size returned or
4017 None on error
4018 """
4019 try:
4020 # TODO: Should this check against the number of elements returned
4021 # and then return true/false based on that?
4022 setName = str( setName ).strip()
4023 # Patterns to match
4024 setPattern = "\[(.*)\]"
4025 pattern = "There are (\d+) items in set " + setName + ":\n" +\
4026 setPattern
4027 cmdStr = "set-test-get -s "
4028 cmdStr += setName
4029 output = self.sendline( cmdStr )
4030 try:
4031 # TODO: Maybe make this less hardcoded
4032 # ConsistentMap Exceptions
4033 assert "org.onosproject.store.service" not in output
4034 # Node not leader
4035 assert "java.lang.IllegalStateException" not in output
4036 except AssertionError:
4037 main.log.error( "Error in processing '" + cmdStr + "' " +
4038 "command: " + str( output ) )
4039 retryTime = 30 # Conservative time, given by Madan
4040 main.log.info( "Waiting " + str( retryTime ) +
4041 "seconds before retrying." )
4042 time.sleep( retryTime ) # Due to change in mastership
4043 output = self.sendline( cmdStr )
4044 assert "Command not found:" not in output, output
4045 assert "Error executing command" not in output, output
4046 main.log.info( self.name + ": " + output )
4047 match = re.search( pattern, output )
4048 if match:
4049 setSize = int( match.group( 1 ) )
4050 setMatch = match.group( 2 )
4051 if len( setMatch.split() ) == setSize:
4052 main.log.info( "The size returned by " + self.name +
4053 " matches the number of elements in " +
4054 "the returned set" )
4055 else:
4056 main.log.error( "The size returned by " + self.name +
4057 " does not match the number of " +
4058 "elements in the returned set." )
4059 return setSize
4060 else: # no match
4061 main.log.error( self.name + ": setTestGet did not" +
4062 " match expected output" )
4063 main.log.debug( self.name + " expected: " + pattern )
4064 main.log.debug( self.name + " actual: " + repr( output ) )
4065 return None
4066 except AssertionError:
4067 main.log.exception( "Error in processing '" + cmdStr + "' command." )
4068 return None
4069 except TypeError:
4070 main.log.exception( self.name + ": Object not as expected" )
4071 return None
4072 except pexpect.EOF:
4073 main.log.error( self.name + ": EOF exception found" )
4074 main.log.error( self.name + ": " + self.handle.before )
4075 main.cleanup()
4076 main.exit()
4077 except Exception:
4078 main.log.exception( self.name + ": Uncaught exception!" )
4079 main.cleanup()
4080 main.exit()
4081
4082 def counters( self, jsonFormat=True ):
4083 """
4084 Command to list the various counters in the system.
4085 returns:
4086 if jsonFormat, a string of the json object returned by the cli
4087 command
4088 if not jsonFormat, the normal string output of the cli command
4089 None on error
4090 """
4091 try:
4092 counters = {}
4093 cmdStr = "counters"
4094 if jsonFormat:
4095 cmdStr += " -j"
4096 output = self.sendline( cmdStr )
4097 assert "Command not found:" not in output, output
4098 assert "Error executing command" not in output, output
4099 main.log.info( self.name + ": " + output )
4100 return output
4101 except AssertionError:
4102 main.log.exception( "Error in processing 'counters' command." )
4103 return None
4104 except TypeError:
4105 main.log.exception( self.name + ": Object not as expected" )
4106 return None
4107 except pexpect.EOF:
4108 main.log.error( self.name + ": EOF exception found" )
4109 main.log.error( self.name + ": " + self.handle.before )
4110 main.cleanup()
4111 main.exit()
4112 except Exception:
4113 main.log.exception( self.name + ": Uncaught exception!" )
4114 main.cleanup()
4115 main.exit()
4116
4117 def counterTestAddAndGet( self, counter, delta=1, inMemory=False ):
4118 """
4119 CLI command to add a delta to then get a distributed counter.
4120 Required arguments:
4121 counter - The name of the counter to increment.
4122 Optional arguments:
4123 delta - The long to add to the counter
4124 inMemory - use in memory map for the counter
4125 returns:
4126 integer value of the counter or
4127 None on Error
4128 """
4129 try:
4130 counter = str( counter )
4131 delta = int( delta )
4132 cmdStr = "counter-test-increment "
4133 if inMemory:
4134 cmdStr += "-i "
4135 cmdStr += counter
4136 if delta != 1:
4137 cmdStr += " " + str( delta )
4138 output = self.sendline( cmdStr )
4139 try:
4140 # TODO: Maybe make this less hardcoded
4141 # ConsistentMap Exceptions
4142 assert "org.onosproject.store.service" not in output
4143 # Node not leader
4144 assert "java.lang.IllegalStateException" not in output
4145 except AssertionError:
4146 main.log.error( "Error in processing '" + cmdStr + "' " +
4147 "command: " + str( output ) )
4148 retryTime = 30 # Conservative time, given by Madan
4149 main.log.info( "Waiting " + str( retryTime ) +
4150 "seconds before retrying." )
4151 time.sleep( retryTime ) # Due to change in mastership
4152 output = self.sendline( cmdStr )
4153 assert "Command not found:" not in output, output
4154 assert "Error executing command" not in output, output
4155 main.log.info( self.name + ": " + output )
4156 pattern = counter + " was updated to (-?\d+)"
4157 match = re.search( pattern, output )
4158 if match:
4159 return int( match.group( 1 ) )
4160 else:
4161 main.log.error( self.name + ": counterTestAddAndGet did not" +
4162 " match expected output." )
4163 main.log.debug( self.name + " expected: " + pattern )
4164 main.log.debug( self.name + " actual: " + repr( output ) )
4165 return None
4166 except AssertionError:
4167 main.log.exception( "Error in processing '" + cmdStr + "' command." )
4168 return None
4169 except TypeError:
4170 main.log.exception( self.name + ": Object not as expected" )
4171 return None
4172 except pexpect.EOF:
4173 main.log.error( self.name + ": EOF exception found" )
4174 main.log.error( self.name + ": " + self.handle.before )
4175 main.cleanup()
4176 main.exit()
4177 except Exception:
4178 main.log.exception( self.name + ": Uncaught exception!" )
4179 main.cleanup()
4180 main.exit()
4181
4182 def counterTestGetAndAdd( self, counter, delta=1, inMemory=False ):
4183 """
4184 CLI command to get a distributed counter then add a delta to it.
4185 Required arguments:
4186 counter - The name of the counter to increment.
4187 Optional arguments:
4188 delta - The long to add to the counter
4189 inMemory - use in memory map for the counter
4190 returns:
4191 integer value of the counter or
4192 None on Error
4193 """
4194 try:
4195 counter = str( counter )
4196 delta = int( delta )
4197 cmdStr = "counter-test-increment -g "
4198 if inMemory:
4199 cmdStr += "-i "
4200 cmdStr += counter
4201 if delta != 1:
4202 cmdStr += " " + str( delta )
4203 output = self.sendline( cmdStr )
4204 try:
4205 # TODO: Maybe make this less hardcoded
4206 # ConsistentMap Exceptions
4207 assert "org.onosproject.store.service" not in output
4208 # Node not leader
4209 assert "java.lang.IllegalStateException" not in output
4210 except AssertionError:
4211 main.log.error( "Error in processing '" + cmdStr + "' " +
4212 "command: " + str( output ) )
4213 retryTime = 30 # Conservative time, given by Madan
4214 main.log.info( "Waiting " + str( retryTime ) +
4215 "seconds before retrying." )
4216 time.sleep( retryTime ) # Due to change in mastership
4217 output = self.sendline( cmdStr )
4218 assert "Command not found:" not in output, output
4219 assert "Error executing command" not in output, output
4220 main.log.info( self.name + ": " + output )
4221 pattern = counter + " was updated to (-?\d+)"
4222 match = re.search( pattern, output )
4223 if match:
4224 return int( match.group( 1 ) )
4225 else:
4226 main.log.error( self.name + ": counterTestGetAndAdd did not" +
4227 " match expected output." )
4228 main.log.debug( self.name + " expected: " + pattern )
4229 main.log.debug( self.name + " actual: " + repr( output ) )
4230 return None
4231 except AssertionError:
4232 main.log.exception( "Error in processing '" + cmdStr + "' command." )
4233 return None
4234 except TypeError:
4235 main.log.exception( self.name + ": Object not as expected" )
4236 return None
4237 except pexpect.EOF:
4238 main.log.error( self.name + ": EOF exception found" )
4239 main.log.error( self.name + ": " + self.handle.before )
4240 main.cleanup()
4241 main.exit()
4242 except Exception:
4243 main.log.exception( self.name + ": Uncaught exception!" )
4244 main.cleanup()
4245 main.exit()
4246
4247 def summary( self, jsonFormat=True ):
4248 """
4249 Description: Execute summary command in onos
4250 Returns: json object ( summary -j ), returns main.FALSE if there is
4251 no output
4252
4253 """
4254 try:
4255 cmdStr = "summary"
4256 if jsonFormat:
4257 cmdStr += " -j"
4258 handle = self.sendline( cmdStr )
4259 assert "Command not found:" not in handle, handle
4260 assert "Error:" not in handle, handle
4261 if not handle:
4262 main.log.error( self.name + ": There is no output in " +
4263 "summary command" )
4264 return main.FALSE
4265 return handle
4266 except AssertionError:
4267 main.log.exception( "{} Error in summary output:".format( self.name ) )
4268 return None
4269 except TypeError:
4270 main.log.exception( self.name + ": Object not as expected" )
4271 return None
4272 except pexpect.EOF:
4273 main.log.error( self.name + ": EOF exception found" )
4274 main.log.error( self.name + ": " + self.handle.before )
4275 main.cleanup()
4276 main.exit()
4277 except Exception:
4278 main.log.exception( self.name + ": Uncaught exception!" )
4279 main.cleanup()
4280 main.exit()
4281
4282 def transactionalMapGet( self, keyName, inMemory=False ):
4283 """
4284 CLI command to get the value of a key in a consistent map using
4285 transactions. This a test function and can only get keys from the
4286 test map hard coded into the cli command
4287 Required arguments:
4288 keyName - The name of the key to get
4289 Optional arguments:
4290 inMemory - use in memory map for the counter
4291 returns:
4292 The string value of the key or
4293 None on Error
4294 """
4295 try:
4296 keyName = str( keyName )
4297 cmdStr = "transactional-map-test-get "
4298 if inMemory:
4299 cmdStr += "-i "
4300 cmdStr += keyName
4301 output = self.sendline( cmdStr )
4302 assert "Command not found:" not in output, output
4303 try:
4304 # TODO: Maybe make this less hardcoded
4305 # ConsistentMap Exceptions
4306 assert "org.onosproject.store.service" not in output
4307 # Node not leader
4308 assert "java.lang.IllegalStateException" not in output
4309 except AssertionError:
4310 main.log.error( "Error in processing '" + cmdStr + "' " +
4311 "command: " + str( output ) )
4312 return None
4313 pattern = "Key-value pair \(" + keyName + ", (?P<value>.+)\) found."
4314 if "Key " + keyName + " not found." in output:
4315 return None
4316 else:
4317 match = re.search( pattern, output )
4318 if match:
4319 return match.groupdict()[ 'value' ]
4320 else:
4321 main.log.error( self.name + ": transactionlMapGet did not" +
4322 " match expected output." )
4323 main.log.debug( self.name + " expected: " + pattern )
4324 main.log.debug( self.name + " actual: " + repr( output ) )
4325 return None
4326 except AssertionError:
4327 main.log.exception( "" )
4328 return None
4329 except TypeError:
4330 main.log.exception( self.name + ": Object not as expected" )
4331 return None
4332 except pexpect.EOF:
4333 main.log.error( self.name + ": EOF exception found" )
4334 main.log.error( self.name + ": " + self.handle.before )
4335 main.cleanup()
4336 main.exit()
4337 except Exception:
4338 main.log.exception( self.name + ": Uncaught exception!" )
4339 main.cleanup()
4340 main.exit()
4341
4342 def transactionalMapPut( self, numKeys, value, inMemory=False ):
4343 """
4344 CLI command to put a value into 'numKeys' number of keys in a
4345 consistent map using transactions. This a test function and can only
4346 put into keys named 'Key#' of the test map hard coded into the cli command
4347 Required arguments:
4348 numKeys - Number of keys to add the value to
4349 value - The string value to put into the keys
4350 Optional arguments:
4351 inMemory - use in memory map for the counter
4352 returns:
4353 A dictionary whose keys are the name of the keys put into the map
4354 and the values of the keys are dictionaries whose key-values are
4355 'value': value put into map and optionaly
4356 'oldValue': Previous value in the key or
4357 None on Error
4358
4359 Example output
4360 { 'Key1': {'oldValue': 'oldTestValue', 'value': 'Testing'},
4361 'Key2': {'value': 'Testing'} }
4362 """
4363 try:
4364 numKeys = str( numKeys )
4365 value = str( value )
4366 cmdStr = "transactional-map-test-put "
4367 if inMemory:
4368 cmdStr += "-i "
4369 cmdStr += numKeys + " " + value
4370 output = self.sendline( cmdStr )
4371 assert "Command not found:" not in output, output
4372 try:
4373 # TODO: Maybe make this less hardcoded
4374 # ConsistentMap Exceptions
4375 assert "org.onosproject.store.service" not in output
4376 # Node not leader
4377 assert "java.lang.IllegalStateException" not in output
4378 except AssertionError:
4379 main.log.error( "Error in processing '" + cmdStr + "' " +
4380 "command: " + str( output ) )
4381 return None
4382 newPattern = 'Created Key (?P<key>(\w)+) with value (?P<value>(.)+)\.'
4383 updatedPattern = "Put (?P<value>(.)+) into key (?P<key>(\w)+)\. The old value was (?P<oldValue>(.)+)\."
4384 results = {}
4385 for line in output.splitlines():
4386 new = re.search( newPattern, line )
4387 updated = re.search( updatedPattern, line )
4388 if new:
4389 results[ new.groupdict()[ 'key' ] ] = { 'value': new.groupdict()[ 'value' ] }
4390 elif updated:
4391 results[ updated.groupdict()[ 'key' ] ] = { 'value': updated.groupdict()[ 'value' ],
4392 'oldValue': updated.groupdict()[ 'oldValue' ] }
4393 else:
4394 main.log.error( self.name + ": transactionlMapGet did not" +
4395 " match expected output." )
4396 main.log.debug( "{} expected: {!r} or {!r}".format( self.name,
4397 newPattern,
4398 updatedPattern ) )
4399 main.log.debug( self.name + " actual: " + repr( output ) )
4400 return results
4401 except AssertionError:
4402 main.log.exception( "" )
4403 return None
4404 except TypeError:
4405 main.log.exception( self.name + ": Object not as expected" )
4406 return None
4407 except pexpect.EOF:
4408 main.log.error( self.name + ": EOF exception found" )
4409 main.log.error( self.name + ": " + self.handle.before )
4410 main.cleanup()
4411 main.exit()
4412 except Exception:
4413 main.log.exception( self.name + ": Uncaught exception!" )
4414 main.cleanup()
4415 main.exit()
4416
4417 def maps( self, jsonFormat=True ):
4418 """
4419 Description: Returns result of onos:maps
4420 Optional:
4421 * jsonFormat: enable json formatting of output
4422 """
4423 try:
4424 cmdStr = "maps"
4425 if jsonFormat:
4426 cmdStr += " -j"
4427 handle = self.sendline( cmdStr )
4428 assert "Command not found:" not in handle, handle
4429 return handle
4430 except AssertionError:
4431 main.log.exception( "" )
4432 return None
4433 except TypeError:
4434 main.log.exception( self.name + ": Object not as expected" )
4435 return None
4436 except pexpect.EOF:
4437 main.log.error( self.name + ": EOF exception found" )
4438 main.log.error( self.name + ": " + self.handle.before )
4439 main.cleanup()
4440 main.exit()
4441 except Exception:
4442 main.log.exception( self.name + ": Uncaught exception!" )
4443 main.cleanup()
4444 main.exit()
4445
4446 def getSwController( self, uri, jsonFormat=True ):
4447 """
4448 Descrition: Gets the controller information from the device
4449 """
4450 try:
4451 cmd = "device-controllers "
4452 if jsonFormat:
4453 cmd += "-j "
4454 response = self.sendline( cmd + uri )
4455 assert "Command not found:" not in response, response
4456 return response
4457 except AssertionError:
4458 main.log.exception( "" )
4459 return None
4460 except TypeError:
4461 main.log.exception( self.name + ": Object not as expected" )
4462 return None
4463 except pexpect.EOF:
4464 main.log.error( self.name + ": EOF exception found" )
4465 main.log.error( self.name + ": " + self.handle.before )
4466 main.cleanup()
4467 main.exit()
4468 except Exception:
4469 main.log.exception( self.name + ": Uncaught exception!" )
4470 main.cleanup()
4471 main.exit()
4472
4473 def setSwController( self, uri, ip, proto="tcp", port="6653", jsonFormat=True ):
4474 """
4475 Descrition: sets the controller(s) for the specified device
4476
4477 Parameters:
4478 Required: uri - String: The uri of the device(switch).
4479 ip - String or List: The ip address of the controller.
4480 This parameter can be formed in a couple of different ways.
4481 VALID:
4482 10.0.0.1 - just the ip address
4483 tcp:10.0.0.1 - the protocol and the ip address
4484 tcp:10.0.0.1:6653 - the protocol and port can be specified,
4485 so that you can add controllers with different
4486 protocols and ports
4487 INVALID:
4488 10.0.0.1:6653 - this is not supported by ONOS
4489
4490 Optional: proto - The type of connection e.g. tcp, ssl. If a list of ips are given
4491 port - The port number.
4492 jsonFormat - If set ONOS will output in json NOTE: This is currently not supported
4493
4494 Returns: main.TRUE if ONOS returns without any errors, otherwise returns main.FALSE
4495 """
4496 try:
4497 cmd = "device-setcontrollers"
4498
4499 if jsonFormat:
4500 cmd += " -j"
4501 cmd += " " + uri
4502 if isinstance( ip, str ):
4503 ip = [ip]
4504 for item in ip:
4505 if ":" in item:
4506 sitem = item.split( ":" )
4507 if len(sitem) == 3:
4508 cmd += " " + item
4509 elif "." in sitem[1]:
4510 cmd += " {}:{}".format(item, port)
4511 else:
4512 main.log.error( "Malformed entry: " + item )
4513 raise TypeError
4514 else:
4515 cmd += " {}:{}:{}".format( proto, item, port )
4516 response = self.sendline( cmd )
4517 assert "Command not found:" not in response, response
4518 if "Error" in response:
4519 main.log.error( response )
4520 return main.FALSE
4521 return main.TRUE
4522 except AssertionError:
4523 main.log.exception( "" )
4524 return None
4525 except TypeError:
4526 main.log.exception( self.name + ": Object not as expected" )
4527 return main.FALSE
4528 except pexpect.EOF:
4529 main.log.error( self.name + ": EOF exception found" )
4530 main.log.error( self.name + ": " + self.handle.before )
4531 main.cleanup()
4532 main.exit()
4533 except Exception:
4534 main.log.exception( self.name + ": Uncaught exception!" )
4535 main.cleanup()
4536 main.exit()
4537
4538 def removeDevice( self, device ):
4539 '''
4540 Description:
4541 Remove a device from ONOS by passing the uri of the device(s).
4542 Parameters:
4543 device - (str or list) the id or uri of the device ex. "of:0000000000000001"
4544 Returns:
4545 Returns main.FALSE if an exception is thrown or an error is present
4546 in the response. Otherwise, returns main.TRUE.
4547 NOTE:
4548 If a host cannot be removed, then this function will return main.FALSE
4549 '''
4550 try:
4551 if type( device ) is str:
4552 device = list( device )
4553
4554 for d in device:
4555 time.sleep( 1 )
4556 response = self.sendline( "device-remove {}".format( d ) )
4557 assert "Command not found:" not in response, response
4558 if "Error" in response:
4559 main.log.warn( "Error for device: {}\nResponse: {}".format( d, response ) )
4560 return main.FALSE
4561 return main.TRUE
4562 except AssertionError:
4563 main.log.exception( "" )
4564 return main.FALSE
4565 except TypeError:
4566 main.log.exception( self.name + ": Object not as expected" )
4567 return main.FALSE
4568 except pexpect.EOF:
4569 main.log.error( self.name + ": EOF exception found" )
4570 main.log.error( self.name + ": " + self.handle.before )
4571 main.cleanup()
4572 main.exit()
4573 except Exception:
4574 main.log.exception( self.name + ": Uncaught exception!" )
4575 main.cleanup()
4576 main.exit()
4577
4578 def removeHost( self, host ):
4579 '''
4580 Description:
4581 Remove a host from ONOS by passing the id of the host(s)
4582 Parameters:
4583 hostId - (str or list) the id or mac of the host ex. "00:00:00:00:00:01"
4584 Returns:
4585 Returns main.FALSE if an exception is thrown or an error is present
4586 in the response. Otherwise, returns main.TRUE.
4587 NOTE:
4588 If a host cannot be removed, then this function will return main.FALSE
4589 '''
4590 try:
4591 if type( host ) is str:
4592 host = list( host )
4593
4594 for h in host:
4595 time.sleep( 1 )
4596 response = self.sendline( "host-remove {}".format( h ) )
4597 assert "Command not found:" not in response, response
4598 if "Error" in response:
4599 main.log.warn( "Error for host: {}\nResponse: {}".format( h, response ) )
4600 return main.FALSE
4601 return main.TRUE
4602 except AssertionError:
4603 main.log.exception( "" )
4604 return None
4605 except TypeError:
4606 main.log.exception( self.name + ": Object not as expected" )
4607 return main.FALSE
4608 except pexpect.EOF:
4609 main.log.error( self.name + ": EOF exception found" )
4610 main.log.error( self.name + ": " + self.handle.before )
4611 main.cleanup()
4612 main.exit()
4613 except Exception:
4614 main.log.exception( self.name + ": Uncaught exception!" )
4615 main.cleanup()
4616 main.exit()
4617
4618 def link( self, begin, end, state ):
4619 '''
4620 Description:
4621 Bring link down or up in the null-provider.
4622 params:
4623 begin - (string) One end of a device or switch.
4624 end - (string) the other end of the device or switch
4625 returns:
4626 main.TRUE if no exceptions were thrown and no Errors are
4627 present in the resoponse. Otherwise, returns main.FALSE
4628 '''
4629 try:
4630 cmd = "null-link null:{} null:{} {}".format( begin, end, state )
4631 response = self.sendline( cmd, showResponse=True )
4632 assert "Command not found:" not in response, response
4633 if "Error" in response or "Failure" in response:
4634 main.log.error( response )
4635 return main.FALSE
4636 return main.TRUE
4637 except AssertionError:
4638 main.log.exception( "" )
4639 return None
4640 except TypeError:
4641 main.log.exception( self.name + ": Object not as expected" )
4642 return main.FALSE
4643 except pexpect.EOF:
4644 main.log.error( self.name + ": EOF exception found" )
4645 main.log.error( self.name + ": " + self.handle.before )
4646 main.cleanup()
4647 main.exit()
4648 except Exception:
4649 main.log.exception( self.name + ": Uncaught exception!" )
4650 main.cleanup()
4651 main.exit()
4652
ChetanGaonkerf9c2f8b2016-07-19 15:49:41 -07004653 def host_remove( self, hostid ):
4654 try:
4655 cmdStr = "host-remove" + " " + hostid
4656 handle = self.sendline( cmdStr )
4657 assert "Command not found:" not in handle, handle
4658 return handle
4659 except AssertionError:
4660 main.log.exception( "" )
4661 return None
4662 except TypeError:
4663 main.log.exception( self.name + ": Object not as expected" )
4664 return None
4665 except pexpect.EOF:
4666 main.log.error( self.name + ": EOF exception found" )
4667 main.log.error( self.name + ": " + self.handle.before )
4668 main.cleanup()
4669 main.exit()
4670 except Exception:
4671 main.log.exception( self.name + ": Uncaught exception!" )
4672 main.cleanup()
4673 main.exit()
4674
Chetan Gaonker3ff8eae2016-04-12 14:50:26 -07004675if __name__ == '__main__':
Chetan Gaonker3533faa2016-04-25 17:50:14 -07004676 onos_cli = OnosCliDriver(connect = False)
Chetan Gaonker3ff8eae2016-04-12 14:50:26 -07004677 name = 'onos_cli'
4678 user = 'onos'
4679 passwd = 'rocks'
4680 ip = '172.17.0.2'
4681 options = { 'name': '{0}'.format(name), 'onosIp' : '{0}'.format(ip) }
4682 onos_cli.connect(name = 'onoscli', user_name = user, pwd = passwd, ip_address = ip,
4683 port = '8101', options = options)
4684 device_str = onos_cli.devices(jsonFormat = False)
4685 print('Devices: %s' %device_str)
4686 device_json = onos_cli.devices()
4687 print('Device json: %s' %device_json)
4688 routes_str = onos_cli.routes(jsonFormat = False)
4689 print('Routes %s' %routes_str)
4690 flows_json = onos_cli.flows(state = "ADDED")
4691 print('Flows %s' %flows_json)
4692 onos_cli.disconnect()