1
2 """
3 Created on 26-Oct-2012
4
5 author:: Anil Kumar ( anilkumar.s@paxterrasolutions.com )
6
7
8 TestON is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 ( at your option ) any later version.
12
13 TestON is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with TestON. If not, see <http://www.gnu.org/licenses/>.
20
21
22 MininetCliDriver is the basic driver which will handle the Mininet functions
23 """
24 import pexpect
25 import re
26 import sys
27 import os
28 from drivers.common.cli.emulatordriver import Emulator
29
30
32
33 """
34 RemoteMininetCliDriver is the basic driver which will handle the Mininet
35 functions. The main different between this and the MininetCliDriver is that
36 this one does not build the mininet. It assumes that there is already a
37 mininet running on the target.
38 """
40 super( Emulator, self ).__init__()
41 self.handle = self
42 self.name = None
43 self.wrapped = sys.modules[ __name__ ]
44 self.flag = 0
45
46 - def connect( self, **connectargs ):
47 """,user_name, ip_address, pwd,options ):
48 Here the main is the TestON instance after creating all the log
49 handles."""
50 for key in connectargs:
51 vars( self )[ key ] = connectargs[ key ]
52
53 self.name = self.options[ 'name' ]
54
55 try:
56 if os.getenv( str( self.ip_address ) ) != None:
57 self.ip_address = os.getenv( str( self.ip_address ) )
58 else:
59 main.log.info( self.name +
60 ": Trying to connect to " +
61 self.ip_address )
62
63 except KeyError:
64 main.log.info( "Invalid host name," +
65 " connecting to local host instead" )
66 self.ip_address = 'localhost'
67 except Exception as inst:
68 main.log.error( "Uncaught exception: " + str( inst ) )
69
70 self.handle = super(
71 RemoteMininetDriver,
72 self ).connect(
73 user_name=self.user_name,
74 ip_address=self.ip_address,
75 port=None,
76 pwd=self.pwd )
77
78
79 if self.handle:
80 return main.TRUE
81
82 else:
83 main.log.error(
84 "Connection failed to the host " +
85 self.user_name +
86 "@" +
87 self.ip_address )
88 main.log.error( "Failed to connect to the Mininet" )
89 return main.FALSE
90
92 """
93 Returns main.FALSE for 0% packet loss and
94 Returns main.ERROR if "found multiple mininet" is found and
95 Returns main.TRUE else
96 """
97 self.handle.sendline( "" )
98 self.handle.expect( "\$" )
99 self.handle.sendline( "" )
100 self.handle.expect( "\$" )
101 self.handle.sendline( "cat " + pingList )
102 self.handle.expect( pingList )
103 self.handle.expect( "\$" )
104 outputs = self.handle.before + self.handle.after
105 if re.search( " 0% packet loss", outputs ):
106 return main.FALSE
107 elif re.search( "found multiple mininet", outputs ):
108 return main.ERROR
109 else:
110
111 main.log.error( "Error, unexpected output in the ping file" )
112 main.log.warn( outputs )
113 return main.TRUE
114
116 """
117 Starts a continuous ping on the mininet host outputting
118 to a file in the /tmp dir.
119 """
120 self.handle.sendline( "" )
121 self.handle.expect( "\$" )
122 args = utilities.parse_args(
123 [ "SRC", "TARGET", "PINGTIME" ], **pingParams )
124 precmd = "sudo rm /tmp/ping." + args[ "SRC" ]
125 self.execute( cmd=precmd, prompt="(.*)", timeout=10 )
126 command = "sudo mininet/util/m " + args[ "SRC" ] + " ping " +\
127 args[ "TARGET" ] + " -i .2 -w " +\
128 str( args[ 'PINGTIME' ] ) + " -D > /tmp/ping." +\
129 args[ "SRC" ] + " &"
130 main.log.info( command )
131 self.execute( cmd=command, prompt="(.*)", timeout=10 )
132 self.handle.sendline( "" )
133 self.handle.expect( "\$" )
134 return main.TRUE
135
137 """
138 Tails the respective ping output file and check that
139 there is a moving "64 bytes"
140 """
141 self.handle.sendline( "" )
142 self.handle.expect( "\$" )
143 args = utilities.parse_args( [ "SRC" ], **pingParams )
144 self.handle.sendline( "tail /tmp/ping." + args[ "SRC" ] )
145 self.handle.expect( "tail" )
146 self.handle.expect( "\$" )
147 result = self.handle.before + self.handle.after
148 self.handle.sendline( "" )
149 self.handle.expect( "\$" )
150 if re.search( 'Unreachable', result ):
151 main.log.info( "Unreachable found in ping logs..." )
152 return main.FALSE
153 elif re.search( '64\sbytes', result ):
154 main.log.info( "Pings look good" )
155 return main.TRUE
156 else:
157 main.log.info( "No, or faulty ping data..." )
158 return main.FALSE
159
160 - def pingKill( self, testONUser, testONIP ):
161 """
162 Kills all continuous ping processes.
163 Then copies all the ping files to the TestStation.
164 """
165 self.handle.sendline( "" )
166 self.handle.expect( "\$" )
167 command = "sudo kill -SIGINT `pgrep ping`"
168 main.log.info( command )
169 self.execute( cmd=command, prompt="(.*)", timeout=10 )
170
171 main.log.info( "Transferring ping files to TestStation" )
172 command = "scp /tmp/ping.* " + \
173 str( testONUser ) + "@" + str( testONIP ) + ":/tmp/"
174 self.execute( cmd=command, prompt="100%", timeout=20 )
175
176 self.handle.sendline( "" )
177 self.handle.expect( "\$" )
178 self.handle.sendline( "" )
179 self.handle.expect( "\$" )
180 self.handle.sendline( "" )
181 i = self.handle.expect( [ "password", "\$" ] )
182 if i == 0:
183 main.log.error( "Error, sudo asking for password" )
184 main.log.error( self.handle.before )
185 return main.FALSE
186 else:
187 return main.TRUE
188
190 self.handle.sendline( "" )
191 self.handle.expect( "\$" )
192 command = "sudo kill -SIGING `pgrep ping`"
193 main.log.info( command )
194 self.execute( cmd=command, prompt="(.*)", timeout=10 )
195 self.handle.sendline( "" )
196 self.handle.expect( "\$" )
197 return main.TRUE
198
200 """
201 This function is only for Packet Optical related ping
202 Use the next pingHost() function for all normal scenarios )
203 Ping from one mininet host to another
204 Currently the only supported Params: SRC and TARGET
205 """
206 args = utilities.parse_args( [ "SRC", "TARGET" ], **pingParams )
207 command = args[ "SRC" ] + " ping " + \
208 args[ "TARGET" ] + " -c 1 -i 1 -W 8"
209 try:
210 main.log.warn( "Sending: " + command )
211 self.handle.sendline( command )
212 i = self.handle.expect( [ command, pexpect.TIMEOUT ] )
213 if i == 1:
214 main.log.error(
215 self.name +
216 ": timeout when waiting for response from mininet" )
217 main.log.error( "response: " + str( self.handle.before ) )
218 i = self.handle.expect( [ "mininet>", pexpect.TIMEOUT ] )
219 if i == 1:
220 main.log.error(
221 self.name +
222 ": timeout when waiting for response from mininet" )
223 main.log.error( "response: " + str( self.handle.before ) )
224 response = self.handle.before
225 except pexpect.EOF:
226 main.log.error( self.name + ": EOF exception found" )
227 main.log.error( self.name + ": " + self.handle.before )
228 main.cleanup()
229 main.exit()
230 main.log.info( self.name + ": Ping Response: " + response )
231 if re.search( ',\s0\%\spacket\sloss', response ):
232 main.log.info( self.name + ": no packets lost, host is reachable" )
233 main.lastResult = main.TRUE
234 return main.TRUE
235 else:
236 main.log.error(
237 self.name +
238 ": PACKET LOST, HOST IS NOT REACHABLE" )
239 main.lastResult = main.FALSE
240 return main.FALSE
241
243 """
244 Pings between two hosts on remote mininet
245 """
246 self.handle.sendline( "" )
247 self.handle.expect( "\$" )
248 args = utilities.parse_args( [ "SRC", "TARGET" ], **pingParams )
249 command = "mininet/util/m " + \
250 args[ "SRC" ] + " ping " + args[ "TARGET" ] + " -c 4 -W 1 -i .2"
251 main.log.info( command )
252 response = self.execute( cmd=command, prompt="rtt", timeout=10 )
253 if utilities.assert_matches(
254 expect=',\s0\%\spacket\sloss',
255 actual=response,
256 onpass="No Packet loss",
257 onfail="Host is not reachable" ):
258 main.log.info( "NO PACKET LOSS, HOST IS REACHABLE" )
259 main.lastResult = main.TRUE
260 return main.TRUE
261 else:
262 main.log.error( "PACKET LOST, HOST IS NOT REACHABLE" )
263 main.lastResult = main.FALSE
264 return main.FALSE
265
267 """
268 Verifies the correct number of switches are running
269 """
270 if self.handle:
271 self.handle.sendline( "" )
272 self.handle.expect( "\$" )
273 self.handle.sendline( 'ifconfig -a | grep "sw.. " | wc -l' )
274 self.handle.expect( "wc" )
275 self.handle.expect( "\$" )
276 response = self.handle.before
277 self.handle.sendline(
278 'ps -ef | grep "bash -ms mininet:sw" | grep -v color | wc -l' )
279 self.handle.expect( "color" )
280 self.handle.expect( "\$" )
281 response2 = self.handle.before
282
283 if re.search( num, response ):
284 if re.search( num, response2 ):
285 return main.TRUE
286 else:
287 return main.FALSE
288 else:
289 return main.FALSE
290 else:
291 main.log.error( "Connection failed to the host" )
292
293 - def startTcpdump(
294 self,
295 filename,
296 intf="eth0",
297 port="port 6633",
298 user="admin" ):
299 """
300 Runs tcpdump on an interface and saves the file
301 intf can be specified, or the default eth0 is used
302 """
303 try:
304 self.handle.sendline( "" )
305 self.handle.sendline(
306 "sudo tcpdump -n -i " +
307 intf +
308 " " +
309 port +
310 " -w " +
311 filename.strip() +
312 " -Z " +
313 user +
314 " &" )
315 self.handle.sendline( "" )
316 self.handle.sendline( "" )
317 i = self.handle.expect( [ 'No\ssuch\device', 'listening\son',
318 pexpect.TIMEOUT, "\$" ], timeout=10 )
319 main.log.info( self.handle.before + self.handle.after )
320 if i == 0:
321 main.log.error( self.name + ": tcpdump - No such device exists.\
322 tcpdump attempted on: " + intf )
323 return main.FALSE
324 elif i == 1:
325 main.log.info( self.name + ": tcpdump started on " + intf )
326 return main.TRUE
327 elif i == 2:
328 main.log.error( self.name + ": tcpdump command timed out!\
329 Check interface name, given interface was: " + intf )
330 return main.FALSE
331 elif i == 3:
332 main.log.info( self.name + ": " + self.handle.before )
333 return main.TRUE
334 else:
335 main.log.error( self.name + ": tcpdump - unexpected response" )
336 return main.FALSE
337 except pexpect.EOF:
338 main.log.error( self.name + ": EOF exception found" )
339 main.log.error( self.name + ": " + self.handle.before )
340 main.cleanup()
341 main.exit()
342 except Exception:
343 main.log.exception( self.name + ": Uncaught exception!" )
344 main.cleanup()
345 main.exit()
346
348 """
349 pkills tcpdump"""
350 try:
351 self.handle.sendline( "sudo pkill tcpdump" )
352 self.handle.sendline( "" )
353 self.handle.expect( "\$" )
354 except pexpect.EOF:
355 main.log.error( self.name + ": EOF exception found" )
356 main.log.error( self.name + ": " + self.handle.before )
357 main.cleanup()
358 main.exit()
359 except Exception:
360 main.log.exception( self.name + ": Uncaught exception!" )
361 main.cleanup()
362 main.exit()
363
365 import time
366 import types
367 """
368 Description:
369 This function is only meant for Packet Optical.
370 It runs python script "opticalTest.py" to create the
371 packet layer( mn ) and optical topology
372 Optional:
373 name - Name of onos directory. (ONOS | onos)
374 Required:
375 ctrllerIP = Controller(s) IP address
376 TODO: If no ctrllerIP is provided, a default
377 $OC1 can be accepted
378 """
379 try:
380 self.handle.sendline( "" )
381 self.handle.expect( "\$" )
382 self.handle.sendline( "cd ~/" + name + "/tools/test/topos" )
383 self.handle.expect( "topos\$" )
384 if ctrllerIP == None:
385 main.log.info( "You need to specify the IP" )
386 return main.FALSE
387 else:
388 controller = ''
389 if isinstance( ctrllerIP, types.ListType ):
390 for i in xrange( len( ctrllerIP ) ):
391 controller += ctrllerIP[i] + ' '
392 main.log.info( "Mininet topology is being loaded with " +
393 "controllers: " + controller )
394 elif isinstance( ctrllerIP, types.StringType ):
395 controller = ctrllerIP
396 main.log.info( "Mininet topology is being loaded with " +
397 "controller: " + controller )
398 else:
399 main.log.info( "You need to specify a valid IP" )
400 return main.FALSE
401 cmd = "sudo -E python opticalTest.py " + controller
402 main.log.info( self.name + ": cmd = " + cmd )
403 self.handle.sendline( cmd )
404 time.sleep(30)
405 self.handle.sendline( "" )
406 self.handle.sendline( "" )
407 self.handle.expect("mininet>")
408 return main.TRUE
409 except pexpect.EOF:
410 main.log.error( self.name + ": EOF exception found" )
411 main.log.error( self.name + ": " + self.handle.before )
412 return main.FALSE
413
415 """
416 Since executing opticalTest.py will give you mininet
417 prompt, you would at some point require to get onto
418 console of LincOE ((linc@onosTestBench)1>) to execute
419 commands like bring a optical port up or down on a ROADM
420 You can attach to console of Linc-OE session by a cmd:
421 sudo ~/linc-oe/rel/linc/bin/linc attach
422 """
423 try:
424 self.handle.sendline( "" )
425 self.handle.expect( "\$" )
426 self.handle.sendline( "sudo ~/linc-oe/rel/linc/bin/linc attach" )
427 self.handle.expect( ">" )
428 return main.TRUE
429 except pexpect.EOF:
430 main.log.error( self.name + ": EOF exception found" )
431 main.log.error( self.name + ": " + self.handle.before )
432 return main.FALSE
433
435 """
436 Called at the end of the test to disconnect the handle.
437 """
438 if self.handle:
439
440 self.handle.sendline( "" )
441
442 i = self.handle.expect( [ '\$', 'mininet>', pexpect.TIMEOUT,
443 pexpect.EOF ], timeout=2 )
444 if i == 0:
445 self.handle.sendline( "exit" )
446 self.handle.expect( "closed" )
447 elif i == 1:
448 self.handle.sendline( "exit" )
449 self.handle.expect( "exit" )
450 self.handle.expect('\$')
451 self.handle.sendline( "exit" )
452 self.handle.expect( "exit" )
453 self.handle.expect( "closed" )
454 else:
455 main.log.error( "Connection failed to the host" )
456 return main.TRUE
457
458 - def setIpTablesOUTPUT( self, dstIp, dstPort, action='add',
459 packetType='tcp', rule='DROP' ):
460 """
461 Description:
462 add or remove iptables rule to DROP ( default )
463 packets from specific IP and PORT
464 Usage:
465 * specify action ( 'add' or 'remove' )
466 when removing, pass in the same argument as you would add. It will
467 delete that specific rule.
468 * specify the destination ip to block with dstIp
469 * specify destination port to block to dstPort
470 * optional packet type to block ( default tcp )
471 * optional iptables rule ( default DROP )
472 WARNING:
473 * This function uses root privilege iptables command which may result
474 in unwanted network errors. USE WITH CAUTION
475 """
476 import re
477 import time
478
479
480
481
482
483
484
485
486
487
488 time.sleep( 5 )
489
490 actionType = action.lower()
491 if actionType != 'add' and actionType != 'remove':
492 main.log.error(
493 "Invalid action type. 'add' or 'remove' table rule" )
494 if rule != 'DROP' and rule != 'ACCEPT' and rule != 'LOG':
495
496 main.log.error(
497 "Invalid rule. 'DROP' or 'ACCEPT' or 'LOG' only." )
498 return
499 return
500 else:
501
502
503
504
505
506
507
508 if actionType == 'add':
509
510
511
512
513
514
515
516 self.handle.sendline( "" )
517 self.handle.expect( "\$" )
518 self.handle.sendline(
519 "sudo iptables -C OUTPUT -p " +
520 str( packetType ) +
521 " -d " +
522 str( dstIp ) +
523 " --dport " +
524 str( dstPort ) +
525 " -j " +
526 str( rule ) )
527 i = self.handle.expect( [ "iptables:", "\$" ] )
528 print i
529 print self.handle.before
530 print "after: "
531 print self.handle.after
532
533 elif actionType == 'remove':
534
535 self.handle.sendline( "" )
536 self.handle.expect( "\$" )
537 self.handle.sendline(
538 "sudo iptables -C OUTPUT -p " +
539 str( packetType ) +
540 " -d " +
541 str( dstIp ) +
542 " --dport " +
543 str( dstPort ) +
544 " -j " +
545 str( rule ) )
546 self.handle.expect( "\$" )
547 print "before: "
548 print self.handle.before
549 actualString = self.handle.after
550 expectString = "iptables:"
551 print "Actual String:"
552 print actualString
553
554 if re.search( expectString, actualString ):
555 matchResult = main.TRUE
556 else:
557 matchResult = main.FALSE
558
559
560
561
562 if matchResult == main.TRUE:
563
564 if actionType == 'add':
565
566 actionAdd = '-A'
567 try:
568 self.handle.sendline( "" )
569 self.handle.sendline(
570 "sudo iptables " +
571 actionAdd +
572 " OUTPUT -p " +
573 str( packetType ) +
574 " -d " +
575 str( dstIp ) +
576 " --dport " +
577 str( dstPort ) +
578 " -j " +
579 str( rule ) )
580
581 infoString = "Rules added to " + str( self.name )
582 infoString += "iptables rule added to block IP: " + \
583 str( dstIp )
584 infoString += "Port: " + \
585 str( dstPort ) + " Rule: " + str( rule )
586
587 main.log.info( infoString )
588
589 self.handle.expect(
590 [ "\$", pexpect.EOF, pexpect.TIMEOUT ] )
591 except pexpect.TIMEOUT:
592 main.log.error(
593 self.name +
594 ": Timeout exception in setIpTables function" )
595 except Exception:
596 main.log.exception( self.name +
597 ": Uncaught exception!" )
598 main.cleanup()
599 main.exit()
600 else:
601 main.log.error(
602 "Given rule already exists, but attempted to add it" )
603
604 elif matchResult == main.FALSE:
605
606 if actionType == 'remove':
607
608 actionRemove = '-D'
609 try:
610 self.handle.sendline( "" )
611
612 self.handle.sendline(
613 "sudo iptables " +
614 actionRemove +
615 " OUTPUT -p " +
616 str( packetType ) +
617 " -d " +
618 str( dstIp ) +
619 " --dport " +
620 str( dstPort ) +
621 " -j " +
622 str( rule ) )
623
624 infoString = "Rules removed from " + str( self.name )
625 infoString += " iptables rule removed \
626 from blocking IP: " + \
627 str( dstIp )
628 infoString += " Port: " + \
629 str( dstPort ) + " Rule: " + str( rule )
630
631 main.log.info( infoString )
632
633 self.handle.expect(
634 [ "\$", pexpect.EOF, pexpect.TIMEOUT ] )
635 except pexpect.TIMEOUT:
636 main.log.error(
637 self.name +
638 ": Timeout exception in setIpTables function" )
639 except Exception:
640 main.log.exception( self.name +
641 ": Uncaught exception!" )
642 main.cleanup()
643 main.exit()
644 else:
645 main.log.error(
646 "Given rule does not exist,\
647 but attempted to remove it" )
648 else:
649
650
651 main.log.error( "Bad rule given for iptables. Exiting..." )
652 main.cleanup()
653 main.exit()
654
655
656 if __name__ != "__main__":
657 import sys
658 sys.modules[ __name__ ] = RemoteMininetDriver()
659