Add pmonitor() to make it easy to monitor popen objects.

This commit is contained in:
Bob Lantz
2012-04-13 17:42:37 -07:00
parent 237a3c54cf
commit 50cebe6753
2 changed files with 68 additions and 16 deletions
+21 -15
View File
@@ -1,30 +1,36 @@
#!/usr/bin/python #!/usr/bin/python
""" """
This example tests the Host.popen()/pexec() interface This example monitors a number of hosts using host.popen() and
pmonitor()
""" """
from mininet.net import Mininet from mininet.net import Mininet
from mininet.node import CPULimitedHost from mininet.node import CPULimitedHost
from mininet.topo import SingleSwitchTopo from mininet.topo import SingleSwitchTopo
from mininet.log import setLogLevel from mininet.log import setLogLevel
# from mininet.cli import CLI from mininet.util import custom, pmonitor
from mininet.util import custom
def testpopen(sched='cfs'): def monitorhosts( hosts=5, sched='cfs' ):
"Test popen() interface" "Start a bunch of pings and monitor them using popen"
host = custom( CPULimitedHost, cpu=.2, sched=sched ) mytopo = SingleSwitchTopo( hosts )
net = Mininet( SingleSwitchTopo( 2 ), host=host ) cpu = .5 / hosts
myhost = custom( CPULimitedHost, cpu=cpu, sched=sched )
net = Mininet( topo=mytopo, host=myhost )
net.start() net.start()
h1 = net.get( 'h1' ) # Start a bunch of pings
# CLI(net) popens = {}
out, err, code = h1.pexec( 'ifconfig' ) last = net.hosts[ -1 ]
print 'stdout:', out.strip() for host in net.hosts:
print 'stderr:', err.strip() popens[ host ] = host.popen( "ping -c5 %s" % last.IP() )
print 'exit code:', code last = host
# Monitor them and print output
for host, line in pmonitor( popens ):
if host:
print "<%s>: %s" % ( host.name, line.strip() )
# Done
net.stop() net.stop()
if __name__ == '__main__': if __name__ == '__main__':
setLogLevel( 'info' ) setLogLevel( 'info' )
testpopen('rt') monitorhosts( hosts=5 )
testpopen('cfs')
+47 -1
View File
@@ -1,11 +1,14 @@
"Utility functions for Mininet." "Utility functions for Mininet."
from mininet.log import output, info, error
from time import sleep from time import sleep
from resource import setrlimit, RLIMIT_NPROC, RLIMIT_NOFILE from resource import setrlimit, RLIMIT_NPROC, RLIMIT_NOFILE
from select import poll, POLLIN from select import poll, POLLIN
from subprocess import call, check_call, Popen, PIPE, STDOUT from subprocess import call, check_call, Popen, PIPE, STDOUT
from mininet.log import output, info, error
import re import re
from fcntl import fcntl, F_GETFL, F_SETFL
from os import O_NONBLOCK
# Command execution support # Command execution support
@@ -300,6 +303,49 @@ def makeNumeric( s ):
else: else:
return s return s
# Popen support
def pmonitor(popens, timeoutms=500, readline=True,
readmax=1024 ):
"""Monitor dict of hosts to popen objects
a line at a time
timeoutms: timeout for poll()
readline: return single line of output
yields: host, line/output (if any)
terminates: when all EOFs received"""
poller = poll()
fdToHost = {}
for host, popen in popens.iteritems():
fd = popen.stdout.fileno()
fdToHost[ fd ] = host
poller.register( fd, POLLIN )
if not readline:
# Use non-blocking reads
flags = fcntl( fd, F_GETFL )
fcntl( fd, F_SETFL, flags | O_NONBLOCK )
while True:
fds = poller.poll( timeoutms )
if fds:
for fd, _event in fds:
host = fdToHost[ fd ]
popen = popens[ host ]
if readline:
# Attempt to read a line of output
# This blocks until we receive a newline!
line = popen.stdout.readline()
else:
line = popen.stdout.read( readmax )
yield host, line
# Check for EOF
if not line:
popen.poll()
if popen.returncode is not None:
poller.unregister( fd )
del popens[ host ]
if not popens:
return
else:
yield None, ''
# Other stuff we use # Other stuff we use