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