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