Python 3 Compatibility (Merge pull request #817 from lantz/py3-compat)
Changes for compatibility with Python 3. The approach is to make as few changes as possible to maintain compatibility with both Python 2 and Python 3. We use whatever python is installed, and also support a PYTHON environment variable for installing another version. For simplicity, we provide mininet.util.pexpect which works out of the box with Python 3 utf-8 strings. Thanks to @cuihantao for looking at this as well and also for changes to MiniEdit. Closes #794
This commit is contained in:
+15
-11
@@ -4,28 +4,32 @@ sudo: required
|
||||
matrix:
|
||||
include:
|
||||
- dist: trusty
|
||||
python: 2.7
|
||||
env: dist="14.04 LTS trusty"
|
||||
- dist: trusty
|
||||
python: 3.6
|
||||
env: dist="14.04 LTS trusty"
|
||||
# - dist: xenial
|
||||
# env: dist="16.04 LTS xenial"
|
||||
# Travis-CI only proposes 14.04 LTS Trusty and there is no plan to update to 16.04 xenial
|
||||
# (c.f. https://github.com/travis-ci/travis-ci/issues/5821)
|
||||
# It is useless to add a second job because it will run in the same Ubuntu version (14.04)
|
||||
|
||||
before_install:
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq vlan
|
||||
- sudo util/install.sh -n
|
||||
- PYTHON=`which python` util/install.sh -n
|
||||
|
||||
install:
|
||||
- bash -c "if [ `lsb_release -rs` == '14.04' ]; then make codecheck; fi"
|
||||
- sudo util/install.sh -fnvw
|
||||
- pip install pexpect || pip3 install pexpect
|
||||
- util/install.sh -nfvw
|
||||
|
||||
script:
|
||||
- sudo mn --test pingall
|
||||
- sudo python mininet/test/runner.py -v -quick
|
||||
- sudo python examples/test/runner.py -v -quick
|
||||
- alias sudo="sudo env PATH=$PATH"
|
||||
- export PYTHON=`which python`
|
||||
- echo 'px import sys; print(sys.version_info)' | sudo $PYTHON bin/mn -v output
|
||||
- sudo $PYTHON bin/mn --test pingall
|
||||
- sudo $PYTHON mininet/test/runner.py -v -quick
|
||||
- sudo $PYTHON examples/test/runner.py -v -quick
|
||||
|
||||
notifications:
|
||||
email:
|
||||
on_success: never
|
||||
# More details: https://docs.travis-ci.com/user/notifications#Configuring-email-notifications
|
||||
|
||||
# More details: https://docs.travis-ci.com/user/notifications
|
||||
|
||||
@@ -2,7 +2,8 @@ MININET = mininet/*.py
|
||||
TEST = mininet/test/*.py
|
||||
EXAMPLES = mininet/examples/*.py
|
||||
MN = bin/mn
|
||||
PYMN = python -B bin/mn
|
||||
PYTHON ?= python
|
||||
PYMN = $(PYTHON) -B bin/mn
|
||||
BIN = $(MN)
|
||||
PYSRC = $(MININET) $(TEST) $(EXAMPLES) $(BIN)
|
||||
MNEXEC = mnexec
|
||||
@@ -54,13 +55,13 @@ install-manpages: $(MANPAGES)
|
||||
install -D -t $(MANDIR) $(MANPAGES)
|
||||
|
||||
install: install-mnexec install-manpages
|
||||
python setup.py install
|
||||
$(PYTHON) setup.py install
|
||||
|
||||
develop: $(MNEXEC) $(MANPAGES)
|
||||
# Perhaps we should link these as well
|
||||
install $(MNEXEC) $(BINDIR)
|
||||
install $(MANPAGES) $(MANDIR)
|
||||
python setup.py develop
|
||||
$(PYTHON) setup.py develop
|
||||
|
||||
man: $(MANPAGES)
|
||||
|
||||
|
||||
@@ -186,8 +186,10 @@ class MininetRunner( object ):
|
||||
for fileName in files:
|
||||
customs = {}
|
||||
if os.path.isfile( fileName ):
|
||||
execfile( fileName, customs, customs )
|
||||
for name, val in customs.iteritems():
|
||||
# pylint: disable=exec-used
|
||||
exec( compile( open( fileName ).read(), fileName, 'exec' ),
|
||||
customs, customs )
|
||||
for name, val in customs.items():
|
||||
self.setCustom( name, val )
|
||||
else:
|
||||
raise Exception( 'could not find custom file: %s' % fileName )
|
||||
@@ -256,7 +258,7 @@ class MininetRunner( object ):
|
||||
opts.add_option( '--arp', action='store_true',
|
||||
default=False, help='set all-pairs ARP entries' )
|
||||
opts.add_option( '--verbosity', '-v', type='choice',
|
||||
choices=LEVELS.keys(), default = 'info',
|
||||
choices=list( LEVELS.keys() ), default = 'info',
|
||||
help = '|'.join( LEVELS.keys() ) )
|
||||
opts.add_option( '--innamespace', action='store_true',
|
||||
default=False, help='sw and ctrl in namespace?' )
|
||||
@@ -286,7 +288,7 @@ class MininetRunner( object ):
|
||||
metavar='server1,server2...',
|
||||
help=( 'run on multiple servers (experimental!)' ) )
|
||||
opts.add_option( '--placement', type='choice',
|
||||
choices=PLACEMENT.keys(), default='block',
|
||||
choices=list( PLACEMENT.keys() ), default='block',
|
||||
metavar='block|random',
|
||||
help=( 'node placement for --cluster '
|
||||
'(experimental!) ' ) )
|
||||
|
||||
+1
-1
@@ -126,7 +126,7 @@ class ClusterCleanup( object ):
|
||||
def cleanup( cls ):
|
||||
"Clean up"
|
||||
info( '*** Cleaning up cluster\n' )
|
||||
for server, user in cls.serveruser.iteritems():
|
||||
for server, user in cls.serveruser.items():
|
||||
if server == 'localhost':
|
||||
# Handled by mininet.clean.cleanup()
|
||||
continue
|
||||
|
||||
@@ -49,7 +49,7 @@ class MininetFacade( object ):
|
||||
args: unnamed networks passed as arguments
|
||||
kwargs: named networks passed as arguments"""
|
||||
self.net = net
|
||||
self.nets = [ net ] + list( args ) + kwargs.values()
|
||||
self.nets = [ net ] + list( args ) + list( kwargs.values() )
|
||||
self.nameToNet = kwargs
|
||||
self.nameToNet['net'] = net
|
||||
|
||||
|
||||
+5
-4
@@ -31,9 +31,9 @@ rate includes buffering.
|
||||
from mininet.net import Mininet
|
||||
from mininet.node import CPULimitedHost
|
||||
from mininet.topolib import TreeTopo
|
||||
from mininet.util import custom, waitListening
|
||||
from mininet.util import custom, waitListening, decode
|
||||
from mininet.log import setLogLevel, info
|
||||
|
||||
from mininet.clean import cleanup
|
||||
|
||||
def bwtest( cpuLimits, period_us=100000, seconds=10 ):
|
||||
"""Example/test of link and CPU bandwidth limits
|
||||
@@ -55,7 +55,8 @@ def bwtest( cpuLimits, period_us=100000, seconds=10 ):
|
||||
net = Mininet( topo=topo, host=host )
|
||||
# pylint: disable=bare-except
|
||||
except:
|
||||
info( '*** Skipping scheduler %s\n' % sched )
|
||||
info( '*** Skipping scheduler %s and cleaning up\n' % sched )
|
||||
cleanup()
|
||||
break
|
||||
net.start()
|
||||
net.pingAll()
|
||||
@@ -70,7 +71,7 @@ def bwtest( cpuLimits, period_us=100000, seconds=10 ):
|
||||
# ignore empty result from waitListening/telnet
|
||||
popen.stdout.readline()
|
||||
client.cmd( 'iperf -yc -t %s -c %s' % ( seconds, server.IP() ) )
|
||||
result = popen.stdout.readline().split( ',' )
|
||||
result = decode( popen.stdout.readline() ).split( ',' )
|
||||
bps = float( result[ -1 ] )
|
||||
popen.terminate()
|
||||
net.stop()
|
||||
|
||||
+27
-12
@@ -20,24 +20,39 @@ OpenFlow icon from https://www.opennetworking.org/
|
||||
|
||||
MINIEDIT_VERSION = '2.2.0.1'
|
||||
|
||||
import sys
|
||||
from optparse import OptionParser
|
||||
# from Tkinter import *
|
||||
from Tkinter import ( Frame, Label, LabelFrame, Entry, OptionMenu, Checkbutton,
|
||||
Menu, Toplevel, Button, BitmapImage, PhotoImage, Canvas,
|
||||
Scrollbar, Wm, TclError, StringVar, IntVar,
|
||||
E, W, EW, NW, Y, VERTICAL, SOLID, CENTER,
|
||||
RIGHT, LEFT, BOTH, TRUE, FALSE )
|
||||
from subprocess import call
|
||||
|
||||
# pylint: disable=import-error
|
||||
if sys.version_info[0] == 2:
|
||||
from Tkinter import ( Frame, Label, LabelFrame, Entry, OptionMenu,
|
||||
Checkbutton, Menu, Toplevel, Button, BitmapImage,
|
||||
PhotoImage, Canvas, Scrollbar, Wm, TclError,
|
||||
StringVar, IntVar, E, W, EW, NW, Y, VERTICAL, SOLID,
|
||||
CENTER, RIGHT, LEFT, BOTH, TRUE, FALSE )
|
||||
from ttk import Notebook
|
||||
from tkMessageBox import showerror
|
||||
from subprocess import call
|
||||
import tkFont
|
||||
import tkFileDialog
|
||||
import tkSimpleDialog
|
||||
else:
|
||||
from tkinter import ( Frame, Label, LabelFrame, Entry, OptionMenu,
|
||||
Checkbutton, Menu, Toplevel, Button, BitmapImage,
|
||||
PhotoImage, Canvas, Scrollbar, Wm, TclError,
|
||||
StringVar, IntVar, E, W, EW, NW, Y, VERTICAL, SOLID,
|
||||
CENTER, RIGHT, LEFT, BOTH, TRUE, FALSE )
|
||||
from tkinter.ttk import Notebook
|
||||
from tkinter.messagebox import showerror
|
||||
from tkinter import font as tkFont
|
||||
from tkinter import simpledialog as tkSimpleDialog
|
||||
from tkinter import filedialog as tkFileDialog
|
||||
# pylint: enable=import-error
|
||||
|
||||
import re
|
||||
import json
|
||||
from distutils.version import StrictVersion
|
||||
import os
|
||||
import sys
|
||||
from functools import partial
|
||||
|
||||
if 'PYTHONPATH' in os.environ:
|
||||
@@ -1408,7 +1423,7 @@ class MiniEdit( Frame ):
|
||||
def convertJsonUnicode(self, text):
|
||||
"Some part of Mininet don't like Unicode"
|
||||
if isinstance(text, dict):
|
||||
return {self.convertJsonUnicode(key): self.convertJsonUnicode(value) for key, value in text.iteritems()}
|
||||
return {self.convertJsonUnicode(key): self.convertJsonUnicode(value) for key, value in text.items()}
|
||||
elif isinstance(text, list):
|
||||
return [self.convertJsonUnicode(element) for element in text]
|
||||
elif isinstance(text, unicode):
|
||||
@@ -1835,7 +1850,7 @@ class MiniEdit( Frame ):
|
||||
|
||||
# Save Links
|
||||
f.write(" info( '*** Add links\\n')\n")
|
||||
for key,linkDetail in self.links.iteritems():
|
||||
for key,linkDetail in self.links.items():
|
||||
tags = self.canvas.gettags(key)
|
||||
if 'data' in tags:
|
||||
optsExist = False
|
||||
@@ -2875,7 +2890,7 @@ class MiniEdit( Frame ):
|
||||
def buildLinks( self, net):
|
||||
# Make links
|
||||
info( "Getting Links.\n" )
|
||||
for key,link in self.links.iteritems():
|
||||
for key,link in self.links.items():
|
||||
tags = self.canvas.gettags(key)
|
||||
if 'data' in tags:
|
||||
src=link['src']
|
||||
@@ -3211,7 +3226,7 @@ class MiniEdit( Frame ):
|
||||
customs = {}
|
||||
if os.path.isfile( fileName ):
|
||||
execfile( fileName, customs, customs )
|
||||
for name, val in customs.iteritems():
|
||||
for name, val in customs.items():
|
||||
self.setCustom( name, val )
|
||||
else:
|
||||
raise Exception( 'could not find custom file: %s' % fileName )
|
||||
|
||||
@@ -9,6 +9,7 @@ monitoring them
|
||||
from mininet.topo import SingleSwitchTopo
|
||||
from mininet.net import Mininet
|
||||
from mininet.log import info, setLogLevel
|
||||
from mininet.util import decode
|
||||
|
||||
from time import time
|
||||
from select import poll, POLLIN
|
||||
@@ -19,7 +20,7 @@ def monitorFiles( outfiles, seconds, timeoutms ):
|
||||
"Monitor set of files and return [(host, line)...]"
|
||||
devnull = open( '/dev/null', 'w' )
|
||||
tails, fdToFile, fdToHost = {}, {}, {}
|
||||
for h, outfile in outfiles.iteritems():
|
||||
for h, outfile in outfiles.items():
|
||||
tail = Popen( [ 'tail', '-f', outfile ],
|
||||
stdout=PIPE, stderr=devnull )
|
||||
fd = tail.stdout.fileno()
|
||||
@@ -40,7 +41,7 @@ def monitorFiles( outfiles, seconds, timeoutms ):
|
||||
host = fdToHost[ fd ]
|
||||
# Wait for a line of output
|
||||
line = f.readline().strip()
|
||||
yield host, line
|
||||
yield host, decode( line )
|
||||
else:
|
||||
# If we timed out, return nothing
|
||||
yield None, ''
|
||||
|
||||
@@ -5,8 +5,9 @@ Tests for baresshd.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
from mininet.clean import cleanup, sh
|
||||
from sys import stdout
|
||||
|
||||
class testBareSSHD( unittest.TestCase ):
|
||||
|
||||
@@ -14,7 +15,9 @@ class testBareSSHD( unittest.TestCase ):
|
||||
|
||||
def connected( self ):
|
||||
"Log into ssh server, check banner, then exit"
|
||||
p = pexpect.spawn( 'ssh 10.0.0.1 -o StrictHostKeyChecking=no -i /tmp/ssh/test_rsa exit' )
|
||||
p = pexpect.spawn( 'ssh 10.0.0.1 -o ConnectTimeout=1 '
|
||||
'-o StrictHostKeyChecking=no '
|
||||
'-i /tmp/ssh/test_rsa exit' )
|
||||
while True:
|
||||
index = p.expect( self.opts )
|
||||
if index == 0:
|
||||
@@ -22,6 +25,7 @@ class testBareSSHD( unittest.TestCase ):
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def setUp( self ):
|
||||
# verify that sshd is not running
|
||||
self.assertFalse( self.connected() )
|
||||
@@ -55,7 +59,7 @@ class testBareSSHD( unittest.TestCase ):
|
||||
|
||||
def tearDown( self ):
|
||||
# kill the ssh process
|
||||
sh( "ps aux | grep 'ssh.*Banner' | awk '{ print $2 }' | xargs kill" )
|
||||
sh( "ps aux | grep ssh |grep Banner| awk '{ print $2 }' | xargs kill" )
|
||||
cleanup()
|
||||
# remove public key pair
|
||||
sh( 'rm -rf /tmp/ssh' )
|
||||
|
||||
@@ -5,7 +5,7 @@ Tests for bind.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
|
||||
class testBind( unittest.TestCase ):
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ A simple sanity check test for cluster edition
|
||||
'''
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
|
||||
class clusterSanityCheck( unittest.TestCase ):
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Tests for controllers.py and controllers2.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
|
||||
class testControllers( unittest.TestCase ):
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for controlnet.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
|
||||
class testControlNet( unittest.TestCase ):
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ cfs 10% 1.29e+09
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
import sys
|
||||
|
||||
class testCPU( unittest.TestCase ):
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for emptynet.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
|
||||
class testEmptyNet( unittest.TestCase ):
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ Test for hwintf.py
|
||||
import unittest
|
||||
import re
|
||||
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
|
||||
from mininet.log import setLogLevel
|
||||
from mininet.node import Node
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for intfOptions.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
import sys
|
||||
|
||||
class testIntfOptions( unittest.TestCase ):
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for limit.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
import sys
|
||||
|
||||
class testLimit( unittest.TestCase ):
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for linearbandwidth.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
import sys
|
||||
|
||||
class testLinearBandwidth( unittest.TestCase ):
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for linuxrouter.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
from mininet.util import quietRun
|
||||
|
||||
class testLinuxRouter( unittest.TestCase ):
|
||||
|
||||
@@ -6,7 +6,7 @@ validates mininet interfaces against systems interfaces
|
||||
'''
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
|
||||
class testMultiLink( unittest.TestCase ):
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for multiping.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
from collections import defaultdict
|
||||
|
||||
class testMultiPing( unittest.TestCase ):
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for multipoll.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
|
||||
class testMultiPoll( unittest.TestCase ):
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for multitest.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
|
||||
class testMultiTest( unittest.TestCase ):
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for nat.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
from mininet.util import quietRun
|
||||
|
||||
destIP = '8.8.8.8' # Google DNS
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for natnet.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
from mininet.util import quietRun
|
||||
|
||||
class testNATNet( unittest.TestCase ):
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for numberedports.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
from collections import defaultdict
|
||||
from mininet.node import OVSSwitch
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for popen.py and popenpoll.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
|
||||
class testPopen( unittest.TestCase ):
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for scratchnet.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
|
||||
class testScratchNet( unittest.TestCase ):
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for simpleperf.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
import sys
|
||||
from mininet.log import setLogLevel
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for sshd.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
from mininet.clean import sh
|
||||
|
||||
class testSSHD( unittest.TestCase ):
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for tree1024.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
import sys
|
||||
|
||||
class testTree1024( unittest.TestCase ):
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for treeping64.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
import sys
|
||||
|
||||
class testTreePing64( unittest.TestCase ):
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for vlanhost.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
import sys
|
||||
from mininet.util import quietRun
|
||||
|
||||
|
||||
+3
-3
@@ -16,12 +16,13 @@ import time
|
||||
|
||||
from mininet.log import info
|
||||
from mininet.term import cleanUpScreens
|
||||
|
||||
from mininet.util import decode
|
||||
|
||||
def sh( cmd ):
|
||||
"Print a command and send it to the shell"
|
||||
info( cmd + '\n' )
|
||||
return Popen( [ '/bin/sh', '-c', cmd ], stdout=PIPE ).communicate()[ 0 ]
|
||||
result = Popen( [ '/bin/sh', '-c', cmd ], stdout=PIPE ).communicate()[ 0 ]
|
||||
return decode( result )
|
||||
|
||||
def killprocs( pattern ):
|
||||
"Reliably terminate processes matching a pattern (including args)"
|
||||
@@ -76,7 +77,6 @@ class Cleanup( object ):
|
||||
for dp in dps:
|
||||
if dp:
|
||||
sh( 'dpctl deldp ' + dp )
|
||||
|
||||
info( "*** Removing OVS datapaths\n" )
|
||||
dps = sh("ovs-vsctl --timeout=1 list-br").strip().splitlines()
|
||||
if dps:
|
||||
|
||||
+2
-6
@@ -164,7 +164,7 @@ class Intf( object ):
|
||||
method: config method name
|
||||
param: arg=value (ignore if value=None)
|
||||
value may also be list or dict"""
|
||||
name, value = param.items()[ 0 ]
|
||||
name, value = list( param.items() )[ 0 ]
|
||||
f = getattr( self, method, None )
|
||||
if not f or value is None:
|
||||
return
|
||||
@@ -285,11 +285,7 @@ class TCIntf( Intf ):
|
||||
loss=None, max_queue_size=None ):
|
||||
"Internal method: return tc commands for delay and loss"
|
||||
cmds = []
|
||||
if delay and delay < 0:
|
||||
error( 'Negative delay', delay, '\n' )
|
||||
elif jitter and jitter < 0:
|
||||
error( 'Negative jitter', jitter, '\n' )
|
||||
elif loss and ( loss < 0 or loss > 100 ):
|
||||
if loss and ( loss < 0 or loss > 100 ):
|
||||
error( 'Bad loss percentage', loss, '%%\n' )
|
||||
else:
|
||||
# Delay/jitter/loss/max queue size
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"Module dependency utility functions for Mininet."
|
||||
|
||||
from mininet.util import quietRun
|
||||
from mininet.util import quietRun, BaseString
|
||||
from mininet.log import info, error, debug
|
||||
from os import environ
|
||||
|
||||
@@ -28,9 +28,9 @@ def moduleDeps( subtract=None, add=None ):
|
||||
add: string or list of module names to add, if not already loaded"""
|
||||
subtract = subtract if subtract is not None else []
|
||||
add = add if add is not None else []
|
||||
if isinstance( subtract, basestring ):
|
||||
if isinstance( subtract, BaseString ):
|
||||
subtract = [ subtract ]
|
||||
if isinstance( add, basestring ):
|
||||
if isinstance( add, BaseString ):
|
||||
add = [ add ]
|
||||
for mod in subtract:
|
||||
if mod in lsmod():
|
||||
|
||||
+7
-5
@@ -104,7 +104,7 @@ from mininet.nodelib import NAT
|
||||
from mininet.link import Link, Intf
|
||||
from mininet.util import ( quietRun, fixLimits, numCores, ensureRoot,
|
||||
macColonHex, ipStr, ipParse, netParse, ipAdd,
|
||||
waitListening )
|
||||
waitListening, BaseString )
|
||||
from mininet.term import cleanUpScreens, makeTerms
|
||||
|
||||
# Mininet version: should be consistent with README and LICENSE
|
||||
@@ -383,8 +383,8 @@ class Mininet( object ):
|
||||
params: additional link params (optional)
|
||||
returns: link object"""
|
||||
# Accept node objects or names
|
||||
node1 = node1 if not isinstance( node1, basestring ) else self[ node1 ]
|
||||
node2 = node2 if not isinstance( node2, basestring ) else self[ node2 ]
|
||||
node1 = node1 if not isinstance( node1, BaseString ) else self[ node1 ]
|
||||
node2 = node2 if not isinstance( node2, BaseString ) else self[ node2 ]
|
||||
options = dict( params )
|
||||
# Port is optional
|
||||
if port1 is not None:
|
||||
@@ -549,7 +549,8 @@ class Mininet( object ):
|
||||
switch.start( self.controllers )
|
||||
started = {}
|
||||
for swclass, switches in groupby(
|
||||
sorted( self.switches, key=type ), type ):
|
||||
sorted( self.switches,
|
||||
key=lambda s: str( type( s ) ) ), type ):
|
||||
switches = tuple( switches )
|
||||
if hasattr( swclass, 'batchStartup' ):
|
||||
success = swclass.batchStartup( switches )
|
||||
@@ -576,7 +577,8 @@ class Mininet( object ):
|
||||
info( '*** Stopping %i switches\n' % len( self.switches ) )
|
||||
stopped = {}
|
||||
for swclass, switches in groupby(
|
||||
sorted( self.switches, key=type ), type ):
|
||||
sorted( self.switches,
|
||||
key=lambda s: str( type( s ) ) ), type ):
|
||||
switches = tuple( switches )
|
||||
if hasattr( swclass, 'batchShutdown' ):
|
||||
success = swclass.batchShutdown( switches )
|
||||
|
||||
+28
-16
@@ -62,7 +62,8 @@ from time import sleep
|
||||
|
||||
from mininet.log import info, error, warn, debug
|
||||
from mininet.util import ( quietRun, errRun, errFail, moveIntf, isShellBuiltin,
|
||||
numCores, retry, mountCgroups )
|
||||
numCores, retry, mountCgroups, BaseString, decode,
|
||||
encode, Python3 )
|
||||
from mininet.moduledeps import moduleDeps, pathCheck, TUN
|
||||
from mininet.link import Link, Intf, TCIntf, OVSIntf
|
||||
from re import findall
|
||||
@@ -87,6 +88,9 @@ class Node( object ):
|
||||
self.privateDirs = params.get( 'privateDirs', [] )
|
||||
self.inNamespace = params.get( 'inNamespace', inNamespace )
|
||||
|
||||
# Python 3 complains if we don't wait for shell exit
|
||||
self.waitExited = params.get( 'waitExited', Python3 )
|
||||
|
||||
# Stash configuration parameters for future reference
|
||||
self.params = params
|
||||
|
||||
@@ -144,7 +148,9 @@ class Node( object ):
|
||||
master, slave = pty.openpty()
|
||||
self.shell = self._popen( cmd, stdin=slave, stdout=slave, stderr=slave,
|
||||
close_fds=False )
|
||||
self.stdin = os.fdopen( master, 'rw' )
|
||||
# XXX BL: This doesn't seem right, and we should also probably
|
||||
# close our files when we exit...
|
||||
self.stdin = os.fdopen( master, 'r' )
|
||||
self.stdout = self.stdin
|
||||
self.pid = self.shell.pid
|
||||
self.pollOut = select.poll()
|
||||
@@ -171,7 +177,7 @@ class Node( object ):
|
||||
def mountPrivateDirs( self ):
|
||||
"mount private directories"
|
||||
# Avoid expanding a string into a list of chars
|
||||
assert not isinstance( self.privateDirs, basestring )
|
||||
assert not isinstance( self.privateDirs, BaseString )
|
||||
for directory in self.privateDirs:
|
||||
if isinstance( directory, tuple ):
|
||||
# mount given private directory
|
||||
@@ -200,7 +206,9 @@ class Node( object ):
|
||||
params: parameters to Popen()"""
|
||||
# Leave this is as an instance method for now
|
||||
assert self
|
||||
return Popen( cmd, **params )
|
||||
popen = Popen( cmd, **params )
|
||||
debug( '_popen', cmd, popen.pid )
|
||||
return popen
|
||||
|
||||
def cleanup( self ):
|
||||
"Help python collect its garbage."
|
||||
@@ -209,6 +217,9 @@ class Node( object ):
|
||||
# for intfName in self.intfNames():
|
||||
# if self.name in intfName:
|
||||
# quietRun( 'ip link del ' + intfName )
|
||||
if self.waitExited and self.shell:
|
||||
debug( 'waiting for', self.pid, 'to terminate\n' )
|
||||
self.shell.wait()
|
||||
self.shell = None
|
||||
|
||||
# Subshell I/O, commands and control
|
||||
@@ -218,7 +229,7 @@ class Node( object ):
|
||||
maxbytes: maximum number of bytes to return"""
|
||||
count = len( self.readbuf )
|
||||
if count < maxbytes:
|
||||
data = os.read( self.stdout.fileno(), maxbytes - count )
|
||||
data = decode( os.read( self.stdout.fileno(), maxbytes - count ) )
|
||||
self.readbuf += data
|
||||
if maxbytes >= len( self.readbuf ):
|
||||
result = self.readbuf
|
||||
@@ -242,7 +253,7 @@ class Node( object ):
|
||||
def write( self, data ):
|
||||
"""Write data to node.
|
||||
data: string"""
|
||||
os.write( self.stdin.fileno(), data )
|
||||
os.write( self.stdin.fileno(), encode( data ) )
|
||||
|
||||
def terminate( self ):
|
||||
"Send kill signal to Node and clean up after it."
|
||||
@@ -376,7 +387,7 @@ class Node( object ):
|
||||
if isinstance( args[ 0 ], list ):
|
||||
# popen([cmd, arg1, arg2...])
|
||||
cmd = args[ 0 ]
|
||||
elif isinstance( args[ 0 ], basestring ):
|
||||
elif isinstance( args[ 0 ], BaseString ):
|
||||
# popen("cmd arg1 arg2...")
|
||||
cmd = args[ 0 ].split()
|
||||
else:
|
||||
@@ -400,7 +411,7 @@ class Node( object ):
|
||||
# Warning: this can fail with large numbers of fds!
|
||||
out, err = popen.communicate()
|
||||
exitcode = popen.wait()
|
||||
return out, err, exitcode
|
||||
return decode( out ), decode( err ), exitcode
|
||||
|
||||
# Interface management, configuration, and routing
|
||||
|
||||
@@ -462,7 +473,7 @@ class Node( object ):
|
||||
"""
|
||||
if not intf:
|
||||
return self.defaultIntf()
|
||||
elif isinstance( intf, basestring):
|
||||
elif isinstance( intf, BaseString):
|
||||
return self.nameToIntf[ intf ]
|
||||
else:
|
||||
return intf
|
||||
@@ -489,7 +500,7 @@ class Node( object ):
|
||||
# explicitly so that we won't get errors if we run before they
|
||||
# have been removed by the kernel. Unfortunately this is very slow,
|
||||
# at least with Linux kernels before 2.6.33
|
||||
for intf in self.intfs.values():
|
||||
for intf in list( self.intfs.values() ):
|
||||
# Protect against deleting hardware interfaces
|
||||
if ( self.name in intf.name ) or ( not checkName ):
|
||||
intf.delete()
|
||||
@@ -514,7 +525,7 @@ class Node( object ):
|
||||
"""Set the default route to go through intf.
|
||||
intf: Intf or {dev <intfname> via <gw-ip> ...}"""
|
||||
# Note setParam won't call us if intf is none
|
||||
if isinstance( intf, basestring ) and ' ' in intf:
|
||||
if isinstance( intf, BaseString ) and ' ' in intf:
|
||||
params = intf
|
||||
else:
|
||||
params = 'dev %s' % intf
|
||||
@@ -561,7 +572,7 @@ class Node( object ):
|
||||
method: config method name
|
||||
param: arg=value (ignore if value=None)
|
||||
value may also be list or dict"""
|
||||
name, value = param.items()[ 0 ]
|
||||
name, value = list( param.items() )[ 0 ]
|
||||
if value is None:
|
||||
return
|
||||
f = getattr( self, method, None )
|
||||
@@ -610,7 +621,7 @@ class Node( object ):
|
||||
|
||||
def intfList( self ):
|
||||
"List of our interfaces sorted by port number"
|
||||
return [ self.intfs[ p ] for p in sorted( self.intfs.iterkeys() ) ]
|
||||
return [ self.intfs[ p ] for p in sorted( self.intfs.keys() ) ]
|
||||
|
||||
def intfNames( self ):
|
||||
"The names of our interfaces sorted by port number"
|
||||
@@ -881,7 +892,7 @@ class Switch( Node ):
|
||||
"Return correctly formatted dpid from dpid or switch name (s1 -> 1)"
|
||||
if dpid:
|
||||
# Remove any colons and make sure it's a good hex number
|
||||
dpid = dpid.translate( None, ':' )
|
||||
dpid = dpid.replace( ':', '' )
|
||||
assert len( dpid ) <= self.dpidLen and int( dpid, 16 ) >= 0
|
||||
else:
|
||||
# Use hex of the first number in the switch name
|
||||
@@ -889,6 +900,7 @@ class Switch( Node ):
|
||||
if nums:
|
||||
dpid = hex( int( nums[ 0 ] ) )[ 2: ]
|
||||
else:
|
||||
self.terminate() # Python 3.6 crash workaround
|
||||
raise Exception( 'Unable to derive default datapath ID - '
|
||||
'please either specify a dpid or use a '
|
||||
'canonical switch name such as s23.' )
|
||||
@@ -1232,7 +1244,7 @@ class OVSSwitch( Switch ):
|
||||
run( cmds, shell=True )
|
||||
# Reapply link config if necessary...
|
||||
for switch in switches:
|
||||
for intf in switch.intfs.itervalues():
|
||||
for intf in switch.intfs.values():
|
||||
if isinstance( intf, TCIntf ):
|
||||
intf.config( **intf.params )
|
||||
return switches
|
||||
@@ -1258,7 +1270,7 @@ class OVSSwitch( Switch ):
|
||||
pids = ' '.join( str( switch.pid ) for switch in switches )
|
||||
run( 'kill -HUP ' + pids )
|
||||
for switch in switches:
|
||||
switch.shell = None
|
||||
switch.terminate()
|
||||
return switches
|
||||
|
||||
|
||||
|
||||
@@ -30,10 +30,10 @@ class TestSwitchDpidAssignmentOVS( unittest.TestCase ):
|
||||
def testDefaultDpid( self ):
|
||||
"""Verify that the default dpid is assigned using a valid provided
|
||||
canonical switchname if no dpid is passed in switch creation."""
|
||||
switch = Mininet( Topo(),
|
||||
self.switchClass,
|
||||
Host, Controller ).addSwitch( 's1' )
|
||||
net = Mininet( Topo(), self.switchClass, Host, Controller )
|
||||
switch = net.addSwitch( 's1' )
|
||||
self.assertEqual( switch.defaultDpid(), switch.dpid )
|
||||
net.stop()
|
||||
|
||||
def dpidFrom( self, num ):
|
||||
"Compute default dpid from number"
|
||||
@@ -44,31 +44,34 @@ class TestSwitchDpidAssignmentOVS( unittest.TestCase ):
|
||||
"""Verify that Switch dpid is the actual dpid assigned if dpid is
|
||||
passed in switch creation."""
|
||||
dpid = self.dpidFrom( 0xABCD )
|
||||
switch = Mininet( Topo(), self.switchClass,
|
||||
Host, Controller ).addSwitch(
|
||||
's1', dpid=dpid )
|
||||
net = Mininet( Topo(), self.switchClass, Host, Controller )
|
||||
switch = net.addSwitch( 's1', dpid=dpid )
|
||||
self.assertEqual( switch.dpid, dpid )
|
||||
net.stop()
|
||||
|
||||
def testDefaultDpidAssignmentFailure( self ):
|
||||
"""Verify that Default dpid assignment raises an Exception if the
|
||||
name of the switch does not contin a digit. Also verify the
|
||||
exception message."""
|
||||
net = Mininet( Topo(), self.switchClass, Host, Controller )
|
||||
with self.assertRaises( Exception ) as raises_cm:
|
||||
Mininet( Topo(), self.switchClass,
|
||||
Host, Controller ).addSwitch( 'A' )
|
||||
self.assertEqual(raises_cm.exception.message, 'Unable to derive '
|
||||
net.addSwitch( 'A' )
|
||||
self.assertTrue( 'Unable to derive '
|
||||
'default datapath ID - please either specify a dpid '
|
||||
'or use a canonical switch name such as s23.')
|
||||
'or use a canonical switch name such as s23.'
|
||||
in str( raises_cm.exception ) )
|
||||
net.stop()
|
||||
|
||||
def testDefaultDpidLen( self ):
|
||||
"""Verify that Default dpid length is 16 characters consisting of
|
||||
16 - len(hex of first string of contiguous digits passed in switch
|
||||
name) 0's followed by hex of first string of contiguous digits passed
|
||||
in switch name."""
|
||||
switch = Mininet( Topo(), self.switchClass,
|
||||
Host, Controller ).addSwitch( 's123' )
|
||||
|
||||
net = Mininet( Topo(), self.switchClass, Host, Controller )
|
||||
switch = net.addSwitch( 's123' )
|
||||
self.assertEqual( switch.dpid, self.dpidFrom( 123 ) )
|
||||
net.stop()
|
||||
|
||||
|
||||
class OVSUser( OVSSwitch):
|
||||
"OVS User Switch convenience class"
|
||||
@@ -95,3 +98,4 @@ class testSwitchUserspace( TestSwitchDpidAssignmentOVS ):
|
||||
if __name__ == '__main__':
|
||||
setLogLevel( 'warning' )
|
||||
unittest.main()
|
||||
cleanup()
|
||||
|
||||
@@ -7,13 +7,13 @@ TODO: missing xterm test
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
import os
|
||||
import re
|
||||
from mininet.util import quietRun
|
||||
from mininet.util import quietRun, pexpect
|
||||
from distutils.version import StrictVersion
|
||||
from time import sleep
|
||||
|
||||
|
||||
def tsharkVersion():
|
||||
"Return tshark version"
|
||||
versionStr = quietRun( 'tshark -v' )
|
||||
@@ -95,7 +95,8 @@ class testWalkthrough( unittest.TestCase ):
|
||||
p = pexpect.spawn( 'mn' )
|
||||
p.expect( self.prompt )
|
||||
# Third pattern is a local interface beginning with 'eth' or 'en'
|
||||
interfaces = [ 'h1-eth0', 's1-eth1', r'[^-](eth|en)\w*\d', 'lo',
|
||||
interfaces = [ r'h1-eth0[:\s]', r's1-eth1[:\s]',
|
||||
r'[^-](eth|en)\w*\d[:\s]', r'lo[:\s]',
|
||||
self.prompt ]
|
||||
# h1 ifconfig
|
||||
p.sendline( 'h1 ifconfig -a' )
|
||||
@@ -122,7 +123,7 @@ class testWalkthrough( unittest.TestCase ):
|
||||
ifcount += 1
|
||||
else:
|
||||
break
|
||||
self.assertTrue( ifcount >= 3, 'Missing interfaces on s1')
|
||||
self.assertTrue( ifcount <= 3, 'Missing interfaces on s1')
|
||||
# h1 ps
|
||||
p.sendline( "h1 ps -a | egrep -v 'ps|grep'" )
|
||||
p.expect( self.prompt )
|
||||
@@ -156,9 +157,13 @@ class testWalkthrough( unittest.TestCase ):
|
||||
|
||||
def testSimpleHTTP( self ):
|
||||
"Start an HTTP server on h1 and wget from h2"
|
||||
if 'Python 2' in quietRun( 'python --version' ):
|
||||
httpserver = 'SimpleHTTPServer'
|
||||
else:
|
||||
httpserver = 'http.server'
|
||||
p = pexpect.spawn( 'mn' )
|
||||
p.expect( self.prompt )
|
||||
p.sendline( 'h1 python -m SimpleHTTPServer 80 &' )
|
||||
p.sendline( 'h1 python -m %s 80 &' % httpserver )
|
||||
# The walkthrough doesn't specify a delay here, and
|
||||
# we also don't read the output (also a possible problem),
|
||||
# but for now let's wait a couple of seconds to make
|
||||
@@ -222,8 +227,8 @@ class testWalkthrough( unittest.TestCase ):
|
||||
p.expect( r'rtt min/avg/max/mdev = '
|
||||
r'([\d\.]+)/([\d\.]+)/([\d\.]+)/([\d\.]+) ms' )
|
||||
delay = float( p.match.group( 2 ) )
|
||||
self.assertTrue( delay > 40, 'Delay < 40ms' )
|
||||
self.assertTrue( delay < 45, 'Delay > 40ms' )
|
||||
self.assertTrue( delay >= 40, 'Delay < 40ms' )
|
||||
self.assertTrue( delay <= 50, 'Delay > 50ms' )
|
||||
p.expect( self.prompt )
|
||||
p.sendline( 'exit' )
|
||||
p.wait()
|
||||
@@ -260,7 +265,7 @@ class testWalkthrough( unittest.TestCase ):
|
||||
p.expect( self.prompt )
|
||||
for i in range( 1, 3 ):
|
||||
p.sendline( 'h%d ifconfig' % i )
|
||||
p.expect( 'HWaddr 00:00:00:00:00:0%d' % i )
|
||||
p.expect( r'\s00:00:00:00:00:0%d\s' % i )
|
||||
p.expect( self.prompt )
|
||||
p.sendline( 'exit' )
|
||||
p.expect( pexpect.EOF )
|
||||
@@ -286,7 +291,9 @@ class testWalkthrough( unittest.TestCase ):
|
||||
"Test running user switch in its own namespace"
|
||||
p = pexpect.spawn( 'mn --innamespace --switch user' )
|
||||
p.expect( self.prompt )
|
||||
interfaces = [ 'h1-eth0', 's1-eth1', '[^-]eth0', 'lo', self.prompt ]
|
||||
interfaces = [ r'h1-eth0[:\s]', r's1-eth1[:\s]',
|
||||
r'[^-](eth|en)\w*\d[:\s]', r'lo[:\s]',
|
||||
self.prompt ]
|
||||
p.sendline( 's1 ifconfig -a' )
|
||||
ifcount = 0
|
||||
while True:
|
||||
|
||||
+3
-3
@@ -57,12 +57,12 @@ class MultiGraph( object ):
|
||||
|
||||
def edges_iter( self, data=False, keys=False ):
|
||||
"Iterator: return graph edges, optionally with data and keys"
|
||||
for src, entry in self.edge.iteritems():
|
||||
for dst, entrykeys in entry.iteritems():
|
||||
for src, entry in self.edge.items():
|
||||
for dst, entrykeys in entry.items():
|
||||
if src > dst:
|
||||
# Skip duplicate edges
|
||||
continue
|
||||
for k, attrs in entrykeys.iteritems():
|
||||
for k, attrs in entrykeys.items():
|
||||
if data:
|
||||
if keys:
|
||||
yield( src, dst, k, attrs )
|
||||
|
||||
+58
-12
@@ -12,6 +12,39 @@ from fcntl import fcntl, F_GETFL, F_SETFL
|
||||
from os import O_NONBLOCK
|
||||
import os
|
||||
from functools import partial
|
||||
import sys
|
||||
|
||||
# Python 2/3 compatibility
|
||||
Python3 = sys.version_info[0] == 3
|
||||
BaseString = str if Python3 else getattr( str, '__base__' )
|
||||
Encoding = 'utf-8' if Python3 else None
|
||||
def decode( s ):
|
||||
"Decode a byte string if needed for Python 3"
|
||||
return s.decode( Encoding ) if Python3 else s
|
||||
def encode( s ):
|
||||
"Encode a byte string if needed for Python 3"
|
||||
return s.encode( Encoding ) if Python3 else s
|
||||
try:
|
||||
# pylint: disable=import-error
|
||||
oldpexpect = None
|
||||
import pexpect as oldpexpect
|
||||
# pylint: enable=import-error
|
||||
|
||||
class Pexpect( object ):
|
||||
"Custom pexpect that is compatible with str"
|
||||
@staticmethod
|
||||
def spawn( *args, **kwargs):
|
||||
"pexpect.spawn that is compatible with str"
|
||||
if Python3 and 'encoding' not in kwargs:
|
||||
kwargs.update( encoding='utf-8' )
|
||||
return oldpexpect.spawn( *args, **kwargs )
|
||||
|
||||
def __getattr__( self, name ):
|
||||
return getattr( oldpexpect, name )
|
||||
pexpect = Pexpect()
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
# Command execution support
|
||||
|
||||
@@ -57,7 +90,7 @@ def oldQuietRun( *cmd ):
|
||||
# This is a bit complicated, but it enables us to
|
||||
# monitor command output as it is happening
|
||||
|
||||
# pylint: disable=too-many-branches
|
||||
# pylint: disable=too-many-branches,too-many-statements
|
||||
def errRun( *cmd, **kwargs ):
|
||||
"""Run a command and return stdout, stderr and return code
|
||||
cmd: string or list of command and args
|
||||
@@ -98,6 +131,8 @@ def errRun( *cmd, **kwargs ):
|
||||
f = fdtofile[ fd ]
|
||||
if event & POLLIN:
|
||||
data = f.read( 1024 )
|
||||
if Python3:
|
||||
data = data.decode( Encoding )
|
||||
if echo:
|
||||
output( data )
|
||||
if f == popen.stdout:
|
||||
@@ -116,6 +151,10 @@ def errRun( *cmd, **kwargs ):
|
||||
poller.unregister( fd )
|
||||
|
||||
returncode = popen.wait()
|
||||
# Python 3 complains if we don't explicitly close these
|
||||
popen.stdout.close()
|
||||
if stderr == PIPE:
|
||||
popen.stderr.close()
|
||||
debug( out, err, returncode )
|
||||
return out, err, returncode
|
||||
# pylint: enable=too-many-branches
|
||||
@@ -374,7 +413,7 @@ def pmonitor(popens, timeoutms=500, readline=True,
|
||||
terminates: when all EOFs received"""
|
||||
poller = poll()
|
||||
fdToHost = {}
|
||||
for host, popen in popens.iteritems():
|
||||
for host, popen in popens.items():
|
||||
fd = popen.stdout.fileno()
|
||||
fdToHost[ fd ] = host
|
||||
poller.register( fd, POLLIN )
|
||||
@@ -382,6 +421,13 @@ def pmonitor(popens, timeoutms=500, readline=True,
|
||||
# Use non-blocking reads
|
||||
flags = fcntl( fd, F_GETFL )
|
||||
fcntl( fd, F_SETFL, flags | O_NONBLOCK )
|
||||
|
||||
def readit( f ):
|
||||
"Helper function - read line or data"
|
||||
# Note this will block if readline is True
|
||||
line = f.readline() if readline else f.read( readmax )
|
||||
return decode( line )
|
||||
|
||||
while popens:
|
||||
fds = poller.poll( timeoutms )
|
||||
if fds:
|
||||
@@ -389,15 +435,15 @@ def pmonitor(popens, timeoutms=500, readline=True,
|
||||
host = fdToHost[ fd ]
|
||||
popen = popens[ host ]
|
||||
if event & POLLIN:
|
||||
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 )
|
||||
line = readit( popen.stdout )
|
||||
yield host, line
|
||||
# Check for EOF
|
||||
elif event & POLLHUP:
|
||||
if event & POLLHUP:
|
||||
while True:
|
||||
# Drain buffer
|
||||
line = readit( popen.stdout )
|
||||
yield host, line
|
||||
if line == '':
|
||||
break
|
||||
poller.unregister( fd )
|
||||
del popens[ host ]
|
||||
else:
|
||||
@@ -460,7 +506,7 @@ def fixLimits():
|
||||
|
||||
def mountCgroups():
|
||||
"Make sure cgroups file system is mounted"
|
||||
mounts = quietRun( 'cat /proc/mounts' )
|
||||
mounts = quietRun( 'grep cgroup /proc/mounts' )
|
||||
cgdir = '/sys/fs/cgroup'
|
||||
csdir = cgdir + '/cpuset'
|
||||
if ('cgroup %s' % cgdir not in mounts and
|
||||
@@ -600,7 +646,7 @@ def waitListening( client=None, server='127.0.0.1', port=80, timeout=None ):
|
||||
if not runCmd( 'which telnet' ):
|
||||
raise Exception('Could not find telnet' )
|
||||
# pylint: disable=maybe-no-member
|
||||
serverIP = server if isinstance( server, basestring ) else server.IP()
|
||||
serverIP = server if isinstance( server, BaseString ) else server.IP()
|
||||
cmd = ( 'echo A | telnet -e A %s %s' % ( serverIP, port ) )
|
||||
time = 0
|
||||
result = runCmd( cmd )
|
||||
|
||||
+15
-6
@@ -102,6 +102,14 @@ function version_ge {
|
||||
[ "$1" == "$latest" ]
|
||||
}
|
||||
|
||||
# Attempt to identify Python version
|
||||
PYTHON=${PYTHON:-python}
|
||||
if $PYTHON --version |& grep 'Python 2' > /dev/null; then
|
||||
PYTHON_VERSION=2; PYPKG=python
|
||||
else
|
||||
PYTHON_VERSION=3; PYPKG=python3
|
||||
fi
|
||||
echo "${PYTHON} is version ${PYTHON_VERSION}"
|
||||
|
||||
# Kernel Deb pkg to be removed:
|
||||
KERNEL_IMAGE_OLD=linux-image-2.6.26-33-generic
|
||||
@@ -147,17 +155,18 @@ function mn_deps {
|
||||
ethtool help2man pyflakes pylint python-pep8 python-pexpect
|
||||
elif [ "$DIST" = "SUSE LINUX" ]; then
|
||||
$install gcc make socat psmisc xterm openssh iperf \
|
||||
iproute telnet python-setuptools libcgroup-tools \
|
||||
ethtool help2man python-pyflakes python3-pylint python-pep8 python-pexpect
|
||||
else
|
||||
iproute telnet ${PYPKG}-setuptools libcgroup-tools \
|
||||
ethtool help2man python-pyflakes python3-pylint \
|
||||
python-pep8 ${PYPKG}-pexpect ${PYPKG}-tk
|
||||
else # Debian/Ubuntu
|
||||
$install gcc make socat psmisc xterm ssh iperf iproute2 telnet \
|
||||
python-setuptools cgroup-bin ethtool help2man \
|
||||
pyflakes pylint pep8 python-pexpect
|
||||
cgroup-bin ethtool help2man pyflakes pylint pep8 \
|
||||
${PYPKG}-setuptools ${PYPKG}-pexpect ${PYPKG}-tk
|
||||
fi
|
||||
|
||||
echo "Installing Mininet core"
|
||||
pushd $MININET_DIR/mininet
|
||||
sudo make install
|
||||
sudo PYTHON=${PYTHON} make install
|
||||
popd
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
from subprocess import check_output as co
|
||||
from sys import exit
|
||||
from sys import exit, version_info
|
||||
|
||||
def run(*args, **kwargs):
|
||||
"Run co and decode for python3"
|
||||
result = co(*args, **kwargs)
|
||||
return result.decode() if version_info[ 0 ] >= 3 else result
|
||||
|
||||
# Actually run bin/mn rather than importing via python path
|
||||
version = 'Mininet ' + co( 'PYTHONPATH=. bin/mn --version 2>&1', shell=True )
|
||||
version = 'Mininet ' + run( 'PYTHONPATH=. bin/mn --version 2>&1', shell=True )
|
||||
version = version.strip()
|
||||
|
||||
# Find all Mininet path references
|
||||
lines = co( "egrep -or 'Mininet [0-9\.\+]+\w*' *", shell=True )
|
||||
lines = run( "egrep -or 'Mininet [0-9\.\+]+\w*' *", shell=True )
|
||||
|
||||
error = False
|
||||
|
||||
|
||||
Reference in New Issue
Block a user