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