diff --git a/.github/workflows/code-check.yaml b/.github/workflows/code-check.yaml new file mode 100644 index 0000000..fd35ce4 --- /dev/null +++ b/.github/workflows/code-check.yaml @@ -0,0 +1,22 @@ + +name: code-check + +on: [push, pull_request] + +jobs: + code-check: + name: Mininet Code Check + runs-on: ubuntu-latest + steps: + - name: Set up Python 3.x + uses: actions/setup-python@v2 + with: + python-version: 3.x + - name: Check out Mininet source + uses: actions/checkout@v2 + - name: Install Mininet code check dependencies + run: | + PYTHON=`which python` util/install.sh -n + python -m pip install pylint==2.4.4 + - name: Run code check + run: make codecheck diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 372e716..bfa6b93 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -24,9 +24,6 @@ jobs: # This seems too slow unfortunately: # sudo apt-get upgrade -y -qq PYTHON=`which python` util/install.sh -nv - - name: Run code check (skipping for now) - run: | - bash -c "if [ `lsb_release -rs` == '14.04' ]; then make codecheck; fi" - name: Sanity test run: | export sudo="sudo env PATH=$PATH" diff --git a/.pylint b/.pylint index 22de311..a61fce1 100644 --- a/.pylint +++ b/.pylint @@ -41,10 +41,16 @@ load-plugins= # can either give multiple identifier separated by comma (,) or put this option # multiple time (only on the command line, not in the configuration file where # it should appear only once). +# +# Note: we may want to re-enable some of these at some point, but many of them +# are just style issues rather than errors. +# disable=pointless-except, invalid-name, super-init-not-called, fixme, star-args, - too-many-instance-attributes, too-few-public-methods, too-many-arguments, + too-many-instance-attributes, too-few-public-methods, too-many-locals, too-many-public-methods, duplicate-code, bad-whitespace, - locally-disabled, locally-enabled + locally-disabled, locally-enabled, bad-continuation, + useless-object-inheritance, unnecessary-pass, no-else-return, + no-else-raise, no-else-continue, super-with-arguments # bad-continuation, wrong-import-order diff --git a/.travis.yml b/.travis.yml index 1d184ce..cafb18c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,20 +3,17 @@ sudo: required matrix: include: - - dist: trusty - python: 2.7 - env: dist="14.04 LTS trusty" - - dist: trusty + - dist: focal python: 3.6 - env: dist="14.04 LTS trusty" + env: dist="24.04 LTS focal" before_install: - sudo apt-get update -qq -- sudo apt-get install -qq vlan +- sudo apt-get install -qq vlan pyflakes - PYTHON=`which python` util/install.sh -n install: -- bash -c "if [ `lsb_release -rs` == '14.04' ]; then make codecheck; fi" +- make codecheck - pip install pexpect || pip3 install pexpect - util/install.sh -nfvw diff --git a/Makefile b/Makefile index 752f69c..9e59011 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ BIN = $(MN) PYSRC = $(MININET) $(TEST) $(EXAMPLES) $(BIN) MNEXEC = mnexec MANPAGES = mn.1 mnexec.1 -P8IGN = E251,E201,E302,E202,E126,E127,E203,E226 +P8IGN = E251,E201,E302,E202,E126,E127,E203,E226,E402,W504,W503,E731 PREFIX ?= /usr BINDIR ?= $(PREFIX)/bin MANDIR ?= $(PREFIX)/share/man/man1 diff --git a/bin/mn b/bin/mn index d7f1b2b..3c5a7ec 100755 --- a/bin/mn +++ b/bin/mn @@ -11,15 +11,20 @@ Example to pull custom params (topo, switch, etc.) from a file: sudo mn --custom ~/mininet/custom/custom_example.py """ -from optparse import OptionParser import os import sys import time +from functools import partial +from optparse import OptionParser # pylint: disable=deprecated-module +from sys import exit # pylint: disable=redefined-builtin + # Fix setuptools' evil madness, and open up (more?) security holes if 'PYTHONPATH' in os.environ: sys.path = os.environ[ 'PYTHONPATH' ].split( ':' ) + sys.path +# pylint: disable=wrong-import-position + from mininet.clean import cleanup import mininet.cli from mininet.log import lg, LEVELS, info, debug, warn, error, output @@ -34,10 +39,7 @@ from mininet.link import Link, TCLink, TCULink, OVSLink from mininet.topo import ( SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo, MinimalTopo ) from mininet.topolib import TreeTopo, TorusTopo -from mininet.util import customClass, specialClass, splitArgs -from mininet.util import buildTopo - -from functools import partial +from mininet.util import customClass, specialClass, splitArgs, buildTopo # Experimental! cluster edition prototype from mininet.examples.cluster import ( MininetCluster, RemoteHost, @@ -46,6 +48,7 @@ from mininet.examples.cluster import ( MininetCluster, RemoteHost, ClusterCleanup ) from mininet.examples.clustercli import ClusterCLI + PLACEMENT = { 'block': SwitchBinPlacer, 'random': RandomPlacer } # built in topologies, created only when run @@ -107,6 +110,7 @@ def nullTest( _net ): "Null 'test' (does nothing)" pass + TESTS.update( all=allTest, none=nullTest, build=nullTest ) # Map to alternate spellings of Mininet() methods @@ -425,7 +429,7 @@ if __name__ == "__main__": except KeyboardInterrupt: info( "\n\nKeyboard Interrupt. Shutting down and cleaning up...\n\n") cleanup() - except Exception: + except Exception: # pylint: disable=broad-except # Print exception type_, val_, trace_ = sys.exc_info() errorMsg = ( "-"*80 + "\n" + diff --git a/examples/bind.py b/examples/bind.py index e2a74d7..9a7272a 100755 --- a/examples/bind.py +++ b/examples/bind.py @@ -34,14 +34,14 @@ and '/var/run'. It also has a temporary private directory mounted on '/var/mn' """ +from functools import partial + from mininet.net import Mininet from mininet.node import Host from mininet.cli import CLI from mininet.topo import SingleSwitchTopo from mininet.log import setLogLevel, info -from functools import partial - # Sample usage @@ -61,6 +61,7 @@ def testHostWithPrivateDirs(): CLI( net ) net.stop() + if __name__ == '__main__': setLogLevel( 'info' ) testHostWithPrivateDirs() diff --git a/examples/cluster.py b/examples/cluster.py index 276b71a..78cfbc0 100755 --- a/examples/cluster.py +++ b/examples/cluster.py @@ -74,6 +74,15 @@ Things to do: - hifi support (e.g. delay compensation) """ +from signal import signal, SIGINT, SIG_IGN +from subprocess import Popen, PIPE, STDOUT +import os +from random import randrange +import sys +import re +from itertools import groupby +from operator import attrgetter +from distutils.version import StrictVersion from mininet.node import Node, Host, OVSSwitch, Controller from mininet.link import Link, Intf @@ -85,15 +94,7 @@ from mininet.examples.clustercli import CLI from mininet.log import setLogLevel, debug, info, error from mininet.clean import addCleanupCallback -from signal import signal, SIGINT, SIG_IGN -from subprocess import Popen, PIPE, STDOUT -import os -from random import randrange -import sys -import re -from itertools import groupby -from operator import attrgetter -from distutils.version import StrictVersion +# pylint: disable=too-many-arguments def findUser(): @@ -261,7 +262,7 @@ class RemoteMixin( object ): cmd: remote command to run (list) **params: parameters to Popen() returns: Popen() object""" - if type( cmd ) is str: + if isinstance( cmd, str): cmd = cmd.split() if self.isRemote: if sudo: @@ -289,6 +290,7 @@ class RemoteMixin( object ): def addIntf( self, *args, **kwargs ): "Override: use RemoteLink.moveIntf" # kwargs.update( moveIntfFn=RemoteLink.moveIntf ) + # pylint: disable=useless-super-delegation return super( RemoteMixin, self).addIntf( *args, **kwargs ) @@ -325,6 +327,7 @@ class RemoteOVSSwitch( RemoteMixin, OVSSwitch ): StrictVersion( '1.10' ) ) @classmethod + # pylint: disable=arguments-differ def batchStartup( cls, switches, **_kwargs ): "Start up switches in per-server batches" key = attrgetter( 'server' ) @@ -336,6 +339,7 @@ class RemoteOVSSwitch( RemoteMixin, OVSSwitch ): return switches @classmethod + # pylint: disable=arguments-differ def batchShutdown( cls, switches, **_kwargs ): "Stop switches in per-server batches" key = attrgetter( 'server' ) @@ -413,8 +417,9 @@ class RemoteLink( Link ): # And we can't ssh into this server remotely as 'localhost', # so try again swappping node1 and node2 if node2.server == 'localhost': - return self.makeTunnel( node2, node1, intfname2, intfname1, - addr2, addr1 ) + return self.makeTunnel( node1=node2, node2=node1, + intfname1=intfname2, intfname2=intfname1, + addr1=addr2, addr2=addr1 ) debug( '\n*** Make SSH tunnel ' + node1.server + ':' + intfname1 + ' == ' + node2.server + ':' + intfname2 ) # 1. Create tap interfaces @@ -526,8 +531,9 @@ class RemoteGRELink( RemoteLink ): # We should never try to create a tunnel to ourselves! assert node1.server != node2.server if node2.server == 'localhost': - return self.makeTunnel( node2, node1, intfname2, intfname1, - addr2, addr1 ) + return self.makeTunnel( node1=node2, node2=node1, + intfname1=intfname2, intfname2=intfname1, + addr1=addr2, addr2=addr1 ) IP1, IP2 = node1.serverIP, node2.serverIP # GRE tunnel needs to be set up with the IP of the local interface # that connects the remote node, NOT '127.0.0.1' of localhost @@ -555,6 +561,7 @@ class RemoteGRELink( RemoteLink ): node.rcmd('ip link set dev %s mtu 1450' % intfname) if not self.moveIntf(intfname, node): raise Exception('interface move failed on node %s' % node) + return None # May want to return something useful here # Some simple placement algorithms for MininetCluster @@ -589,10 +596,10 @@ class Placer( object ): class RandomPlacer( Placer ): "Random placement" - def place( self, nodename ): + def place( self, node ): """Random placement function - nodename: node name""" - assert nodename # please pylint + node: node""" + assert node # please pylint # This may be slow with lots of servers return self.servers[ randrange( 0, len( self.servers ) ) ] @@ -606,10 +613,10 @@ class RoundRobinPlacer( Placer ): Placer.__init__( self, *args, **kwargs ) self.next = 0 - def place( self, nodename ): + def place( self, node ): """Round-robin placement function - nodename: node name""" - assert nodename # please pylint + node: node""" + assert node # please pylint # This may be slow with lots of servers server = self.servers[ self.next ] self.next = ( self.next + 1 ) % len( self.servers ) @@ -647,7 +654,7 @@ class SwitchBinPlacer( Placer ): tickets = sum( [ binsizes[ server ] * [ server ] for server in servers ], [] ) # And assign one ticket to each node - return { node: ticket for node, ticket in zip( nodes, tickets ) } + return dict( zip( nodes, tickets ) ) def calculatePlacement( self ): "Pre-calculate node placement" @@ -704,21 +711,21 @@ class HostSwitchBinPlacer( Placer ): self.cset = frozenset( self.controllers ) self.hind, self.sind, self.cind = 0, 0, 0 - def place( self, nodename ): + def place( self, node ): """Simple placement algorithm: place nodes into evenly sized bins""" # Place nodes into bins - if nodename in self.hset: + if node in self.hset: server = self.servdict[ self.hind / self.hbin ] self.hind += 1 - elif nodename in self.sset: + elif node in self.sset: server = self.servdict[ self.sind / self.sbin ] self.sind += 1 - elif nodename in self.cset: + elif node in self.cset: server = self.servdict[ self.cind / self.cbin ] self.cind += 1 else: - info( 'warning: unknown node', nodename ) + info( 'warning: unknown node', node ) server = self.servdict[ 0 ] return server @@ -764,6 +771,7 @@ class MininetCluster( Mininet ): # Make sure control directory exists self.cdir = os.environ[ 'HOME' ] + '/.ssh/mn' errRun( [ 'mkdir', '-p', self.cdir ] ) + # pylint: disable=unexpected-keyword-arg Mininet.__init__( self, *args, **params ) def popen( self, cmd ): @@ -840,18 +848,19 @@ class MininetCluster( Mininet ): if cfile: config.setdefault( 'controlPath', cfile ) + # pylint: disable=arguments-differ,signature-differs def addController( self, *args, **kwargs ): "Patch to update IP address to global IP address" controller = Mininet.addController( self, *args, **kwargs ) loopback = '127.0.0.1' if ( not isinstance( controller, Controller ) or controller.IP() != loopback ): - return + return None # Find route to a different server IP address serverIPs = [ ip for ip in self.serverIP.values() if ip is not controller.IP() ] if not serverIPs: - return # no remote servers - loopback is fine + return None # no remote servers - loopback is fine remoteIP = serverIPs[ 0 ] # Route should contain 'dev ' route = controller.cmd( 'ip route get', remoteIP, @@ -865,6 +874,7 @@ class MininetCluster( Mininet ): debug( controller, 'IP address updated to', controller.IP() ) return controller + # pylint: disable=arguments-differ,signature-differs def buildFromTopo( self, *args, **kwargs ): "Start network" info( '*** Placing nodes\n' ) diff --git a/examples/clusterSanity.py b/examples/clusterSanity.py index 2e1af91..71c2b52 100755 --- a/examples/clusterSanity.py +++ b/examples/clusterSanity.py @@ -17,6 +17,7 @@ def clusterSanity(): CLI( net ) net.stop() + if __name__ == '__main__': setLogLevel( 'info' ) clusterSanity() diff --git a/examples/clustercli.py b/examples/clustercli.py index 68dc686..75cd317 100644 --- a/examples/clustercli.py +++ b/examples/clustercli.py @@ -31,6 +31,7 @@ class ClusterCLI( CLI ): if not nx: try: # pylint: disable=import-error,no-member + # pylint: disable=import-outside-toplevel import networkx nx = networkx # satisfy pylint from matplotlib import pyplot diff --git a/examples/clusterdemo.py b/examples/clusterdemo.py index 3fd21b7..b117ba4 100755 --- a/examples/clusterdemo.py +++ b/examples/clusterdemo.py @@ -19,6 +19,7 @@ def demo(): CLI( net ) net.stop() + if __name__ == '__main__': setLogLevel( 'info' ) demo() diff --git a/examples/clusterperf.py b/examples/clusterperf.py index 2c9486f..ffa48a8 100755 --- a/examples/clusterperf.py +++ b/examples/clusterperf.py @@ -17,6 +17,7 @@ def perf(Link): net.iperf() net.stop() + if __name__ == '__main__': setLogLevel('info') perf( RemoteSSHLink ) diff --git a/examples/consoles.py b/examples/consoles.py index fd92378..6a8aca1 100755 --- a/examples/consoles.py +++ b/examples/consoles.py @@ -27,6 +27,7 @@ Bob Lantz, April 2010 import re +# pylint: disable=import-error from Tkinter import Frame, Button, Label, Text, Scrollbar, Canvas, Wm, READABLE from mininet.log import setLogLevel @@ -34,6 +35,9 @@ from mininet.topolib import TreeNet from mininet.term import makeTerms, cleanUpScreens from mininet.util import quietRun +# pylint: disable=too-many-arguments + + class Console( Frame ): "A simple console on a host." @@ -319,7 +323,7 @@ class ConsoleApp( Frame ): if not m: return val, units = float( m.group( 1 ) ), m.group( 2 ) - #convert to Gbps + # convert to Gbps if units[0] == 'M': val *= 10 ** -3 elif units[0] == 'K': diff --git a/examples/controllers.py b/examples/controllers.py index 952ced4..dad8e5f 100755 --- a/examples/controllers.py +++ b/examples/controllers.py @@ -26,6 +26,7 @@ class MultiSwitch( OVSSwitch ): def start( self, controllers ): return OVSSwitch.start( self, [ cmap[ self.name ] ] ) + topo = TreeTopo( depth=2, fanout=2 ) net = Mininet( topo=topo, switch=MultiSwitch, build=False, waitConnected=True ) for c in [ c0, c1 ]: diff --git a/examples/controllers2.py b/examples/controllers2.py index 3169790..ceefc32 100755 --- a/examples/controllers2.py +++ b/examples/controllers2.py @@ -58,6 +58,7 @@ def multiControllerNet(): info( "*** Stopping network\n" ) net.stop() + if __name__ == '__main__': setLogLevel( 'info' ) # for CLI output multiControllerNet() diff --git a/examples/controlnet.py b/examples/controlnet.py index 257199b..eb7aaa5 100755 --- a/examples/controlnet.py +++ b/examples/controlnet.py @@ -59,13 +59,14 @@ class MininetFacade( object ): def __getitem__( self, key ): "returns primary/named networks or node from any net" - #search kwargs for net named key + # search kwargs for net named key if key in self.nameToNet: return self.nameToNet[ key ] - #search each net for node named key + # search each net for node named key for net in self.nets: if key in net: return net[ key ] + return None def __iter__( self ): "Iterate through all nodes in all Mininet objects" @@ -100,6 +101,7 @@ class MininetFacade( object ): class ControlNetwork( Topo ): "Control Network Topology" + # pylint: disable=arguments-differ def build( self, n, dataController=DataController, **_kwargs ): """n: number of data network controller nodes dataController: class for data network controllers""" diff --git a/examples/cpu.py b/examples/cpu.py index 3878cb9..a5ddded 100755 --- a/examples/cpu.py +++ b/examples/cpu.py @@ -54,7 +54,7 @@ def bwtest( cpuLimits, period_us=100000, seconds=10 ): try: net = Mininet( topo=topo, host=host, waitConnected=True ) # pylint: disable=bare-except - except: + except: # noqa info( '*** Skipping scheduler %s and cleaning up\n' % sched ) cleanup() break diff --git a/examples/emptynet.py b/examples/emptynet.py index fa7da67..474886c 100755 --- a/examples/emptynet.py +++ b/examples/emptynet.py @@ -39,6 +39,7 @@ def emptyNet(): info( '*** Stopping network' ) net.stop() + if __name__ == '__main__': setLogLevel( 'info' ) emptyNet() diff --git a/examples/hwintf.py b/examples/hwintf.py index af90c9b..990beb0 100755 --- a/examples/hwintf.py +++ b/examples/hwintf.py @@ -8,6 +8,8 @@ hardware interface) to a network after the network is created. import re import sys +from sys import exit # pylint: disable=redefined-builtin + from mininet.cli import CLI from mininet.log import setLogLevel, info, error from mininet.net import Mininet @@ -15,6 +17,7 @@ from mininet.link import Intf from mininet.topolib import TreeTopo from mininet.util import quietRun + def checkIntf( intf ): "Make sure intf exists and is not configured." config = quietRun( 'ifconfig %s 2>/dev/null' % intf, shell=True ) @@ -27,6 +30,7 @@ def checkIntf( intf ): 'and is probably in use!\n' ) exit( 1 ) + if __name__ == '__main__': setLogLevel( 'info' ) diff --git a/examples/intfoptions.py b/examples/intfoptions.py index b1b864e..f7373ed 100755 --- a/examples/intfoptions.py +++ b/examples/intfoptions.py @@ -43,6 +43,7 @@ def intfOptions(): info( '\n*** Done testing\n' ) net.stop() + if __name__ == '__main__': setLogLevel( 'info' ) intfOptions() diff --git a/examples/limit.py b/examples/limit.py index 903fd73..a75bb50 100755 --- a/examples/limit.py +++ b/examples/limit.py @@ -55,6 +55,7 @@ def verySimpleLimit( bw=150 ): h2.cmdPrint( 'tc -d class show dev', h2.defaultIntf() ) net.stop() + if __name__ == '__main__': setLogLevel( 'info' ) limit() diff --git a/examples/linearbandwidth.py b/examples/linearbandwidth.py index 1c06ece..e66f36b 100755 --- a/examples/linearbandwidth.py +++ b/examples/linearbandwidth.py @@ -24,20 +24,24 @@ of switches, this example demonstrates: """ +import sys + +from functools import partial + from mininet.net import Mininet from mininet.node import UserSwitch, OVSKernelSwitch, Controller from mininet.topo import Topo from mininet.log import lg, info from mininet.util import irange, quietRun from mininet.link import TCLink -from functools import partial -import sys flush = sys.stdout.flush + class LinearTestTopo( Topo ): "Topology for a string of N hosts and N-1 switches." + # pylint: disable=arguments-differ def build( self, N, **params ): # Create switches and hosts hosts = [ self.addHost( 'h%s' % h ) @@ -79,7 +83,7 @@ def linearBandwidthTest( lengths ): output = quietRun( 'sysctl -w net.ipv4.tcp_congestion_control=reno' ) assert 'reno' in output - for datapath in switches.keys(): + for datapath in switches: info( "*** testing", datapath, "datapath\n" ) Switch = switches[ datapath ] results[ datapath ] = [] @@ -105,7 +109,7 @@ def linearBandwidthTest( lengths ): results[ datapath ] += [ ( n, serverbw ) ] net.stop() - for datapath in switches.keys(): + for datapath in switches: info( "\n*** Linear network results for", datapath, "datapath:\n" ) result = results[ datapath ] info( "SwitchCount\tiperf Results\n" ) @@ -115,6 +119,7 @@ def linearBandwidthTest( lengths ): info( '\n') info( '\n' ) + if __name__ == '__main__': lg.setLogLevel( 'info' ) sizes = [ 1, 2, 3, 4 ] diff --git a/examples/linuxrouter.py b/examples/linuxrouter.py index 37699f3..861c319 100755 --- a/examples/linuxrouter.py +++ b/examples/linuxrouter.py @@ -38,6 +38,7 @@ from mininet.cli import CLI class LinuxRouter( Node ): "A Node with IP forwarding enabled." + # pylint: disable=arguments-differ def config( self, **params ): super( LinuxRouter, self).config( **params ) # Enable forwarding on the router @@ -51,6 +52,7 @@ class LinuxRouter( Node ): class NetworkTopo( Topo ): "A LinuxRouter connecting three IP subnets" + # pylint: disable=arguments-differ def build( self, **_opts ): defaultIP = '192.168.1.1/24' # IP address for r0-eth1 @@ -87,6 +89,7 @@ def run(): CLI( net ) net.stop() + if __name__ == '__main__': setLogLevel( 'info' ) run() diff --git a/examples/miniedit.py b/examples/miniedit.py index aed0f34..a355841 100755 --- a/examples/miniedit.py +++ b/examples/miniedit.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ MiniEdit: a simple network editor for Mininet @@ -13,16 +13,30 @@ Controller icon from http://semlabs.co.uk/ OpenFlow icon from https://www.opennetworking.org/ """ -# Miniedit needs some work in order to pass pylint... -# pylint: disable=line-too-long,too-many-branches -# pylint: disable=too-many-statements,attribute-defined-outside-init -# pylint: disable=missing-docstring - -MINIEDIT_VERSION = '2.2.0.1' - +import json +import os +import re import sys + +from distutils.version import StrictVersion +from functools import partial from optparse import OptionParser from subprocess import call +from sys import exit # pylint: disable=redefined-builtin + +from mininet.log import info, debug, warn, setLogLevel +from mininet.net import Mininet, VERSION +from mininet.util import (netParse, ipAdd, quietRun, + buildTopo, custom, customClass ) +from mininet.term import makeTerm, cleanUpScreens +from mininet.node import (Controller, RemoteController, NOX, OVSController, + CPULimitedHost, Host, Node, + OVSSwitch, UserSwitch, IVSSwitch ) +from mininet.link import TCLink, Intf, Link +from mininet.cli import CLI +from mininet.moduledeps import moduleDeps +from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo +from mininet.topolib import TreeTopo # pylint: disable=import-error if sys.version_info[0] == 2: @@ -47,38 +61,24 @@ else: from tkinter import font as tkFont from tkinter import simpledialog as tkSimpleDialog from tkinter import filedialog as tkFileDialog +# someday: from ttk import * # pylint: enable=import-error -import re -import json -from distutils.version import StrictVersion -import os -from functools import partial + +# Miniedit still needs work in order to pass pylint... +# pylint: disable=line-too-long,too-many-branches +# pylint: disable=too-many-statements,attribute-defined-outside-init +# pylint: disable=missing-docstring,too-many-ancestors +# pylint: disable=too-many-nested-blocks,too-many-arguments + + +MINIEDIT_VERSION = '2.2.0.1' if 'PYTHONPATH' in os.environ: sys.path = os.environ[ 'PYTHONPATH' ].split( ':' ) + sys.path -# someday: from ttk import * - -from mininet.log import info, debug, warn, setLogLevel -from mininet.net import Mininet, VERSION -from mininet.util import netParse, ipAdd, quietRun -from mininet.util import buildTopo -from mininet.util import custom, customClass -from mininet.term import makeTerm, cleanUpScreens -from mininet.node import Controller, RemoteController, NOX, OVSController -from mininet.node import CPULimitedHost, Host, Node -from mininet.node import OVSSwitch, UserSwitch -from mininet.link import TCLink, Intf, Link -from mininet.cli import CLI -from mininet.moduledeps import moduleDeps -from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo -from mininet.topolib import TreeTopo - info( 'MiniEdit running against Mininet '+VERSION, '\n' ) MININET_VERSION = re.sub(r'[^\d\.]', '', VERSION) -if StrictVersion(MININET_VERSION) > StrictVersion('2.0'): - from mininet.node import IVSSwitch TOPODEF = 'none' TOPOS = { 'minimal': lambda: SingleSwitchTopo( k=2 ), @@ -138,6 +138,7 @@ class LegacyRouter( Node ): def __init__( self, name, inNamespace=True, **params ): Node.__init__( self, name, inNamespace, **params ) + # pylint: disable=arguments-differ def config( self, **_params ): if self.intfs: self.setParam( _params, 'setIP', ip='0.0.0.0' ) @@ -818,8 +819,8 @@ class VerticalScrolledTable(LabelFrame): * This frame only allows vertical scrolling """ - def __init__(self, parent, rows=2, columns=2, title=None, *args, **kw): - LabelFrame.__init__(self, parent, text=title, padx=5, pady=5, *args, **kw) + def __init__(self, parent, rows=2, columns=2, title=None, **kw): + LabelFrame.__init__(self, parent, text=title, padx=5, pady=5, **kw) # create a canvas object and a vertical scrollbar for scrolling it vscrollbar = Scrollbar(self, orient=VERTICAL) @@ -855,8 +856,6 @@ class VerticalScrolledTable(LabelFrame): canvas.itemconfigure(interior_id, width=canvas.winfo_width()) canvas.bind('', _configure_canvas) - return - class TableFrame(Frame): def __init__(self, parent, rows=2, columns=2): @@ -888,7 +887,7 @@ class TableFrame(Frame): label.grid(row=self.rows, column=column, sticky="wens", padx=1, pady=1) if value is not None: label.insert(0, value[column]) - if readonly == True: + if readonly: label.configure(state='readonly') current_row.append(label) self._widgets.append(current_row) @@ -1401,11 +1400,11 @@ class MiniEdit( Frame ): def addNode( self, node, nodeNum, x, y, name=None): "Add a new node to our canvas." - if 'Switch' == node: + if node == 'Switch': self.switchCount += 1 - if 'Host' == node: + if node == 'Host': self.hostCount += 1 - if 'Controller' == node: + if node == 'Controller': self.controllerCount += 1 if name is None: name = self.nodePrefixes[ node ] + nodeNum @@ -1422,14 +1421,17 @@ class MiniEdit( Frame ): def convertJsonUnicode(self, text): "Some part of Mininet don't like Unicode" + try: + unicode + except NameError: + return text if isinstance(text, dict): return {self.convertJsonUnicode(key): self.convertJsonUnicode(value) for key, value in text.items()} - elif isinstance(text, list): + if isinstance(text, list): return [self.convertJsonUnicode(element) for element in text] - elif isinstance(text, unicode): + if isinstance(text, unicode): # pylint: disable=undefined-variable return text.encode('utf-8') - else: - return text + return text def loadTopology( self ): "Load command." @@ -1440,7 +1442,7 @@ class MiniEdit( Frame ): ('All Files','*'), ] f = tkFileDialog.askopenfile(filetypes=myFormats, mode='rb') - if f == None: + if f is None: return self.newTopology() loadedTopology = self.convertJsonUnicode(json.load(f)) @@ -1601,10 +1603,11 @@ class MiniEdit( Frame ): for widget in self.widgetToItem: if name == widget[ 'text' ]: return widget + return None def newTopology( self ): "New command." - for widget in self.widgetToItem.keys(): + for widget in self.widgetToItem: self.deleteItem( self.widgetToItem[ widget ] ) self.hostCount = 0 self.switchCount = 0 @@ -1725,7 +1728,7 @@ class MiniEdit( Frame ): if controllerType == 'inband': inBandCtrl = True - if inBandCtrl == True: + if inBandCtrl: f.write("\n") f.write("class InbandController( RemoteController ):\n") f.write("\n") @@ -2122,7 +2125,7 @@ class MiniEdit( Frame ): c = self.canvas x, y = c.canvasx( event.x ), c.canvasy( event.y ) name = self.nodePrefixes[ node ] - if 'Switch' == node: + if node == 'Switch': self.switchCount += 1 name = self.nodePrefixes[ node ] + str( self.switchCount ) self.switchOpts[name] = {} @@ -2130,14 +2133,14 @@ class MiniEdit( Frame ): self.switchOpts[name]['hostname']=name self.switchOpts[name]['switchType']='default' self.switchOpts[name]['controllers']=[] - if 'LegacyRouter' == node: + if node == 'LegacyRouter': self.switchCount += 1 name = self.nodePrefixes[ node ] + str( self.switchCount ) self.switchOpts[name] = {} self.switchOpts[name]['nodeNum']=self.switchCount self.switchOpts[name]['hostname']=name self.switchOpts[name]['switchType']='legacyRouter' - if 'LegacySwitch' == node: + if node == 'LegacySwitch': self.switchCount += 1 name = self.nodePrefixes[ node ] + str( self.switchCount ) self.switchOpts[name] = {} @@ -2145,13 +2148,13 @@ class MiniEdit( Frame ): self.switchOpts[name]['hostname']=name self.switchOpts[name]['switchType']='legacySwitch' self.switchOpts[name]['controllers']=[] - if 'Host' == node: + if node == 'Host': self.hostCount += 1 name = self.nodePrefixes[ node ] + str( self.hostCount ) self.hostOpts[name] = {'sched':'host'} self.hostOpts[name]['nodeNum']=self.hostCount self.hostOpts[name]['hostname']=name - if 'Controller' == node: + if node == 'Controller': name = self.nodePrefixes[ node ] + str( self.controllerCount ) ctrlr = { 'controllerType': 'ref', 'hostname': name, @@ -2169,15 +2172,15 @@ class MiniEdit( Frame ): self.itemToWidget[ item ] = icon self.selectItem( item ) icon.links = {} - if 'Switch' == node: + if node == 'Switch': icon.bind('', self.do_switchPopup ) - if 'LegacyRouter' == node: + if node == 'LegacyRouter': icon.bind('', self.do_legacyRouterPopup ) - if 'LegacySwitch' == node: + if node == 'LegacySwitch': icon.bind('', self.do_legacySwitchPopup ) - if 'Host' == node: + if node == 'Host': icon.bind('', self.do_hostPopup ) - if 'Controller' == node: + if node == 'Controller': icon.bind('', self.do_controllerPopup ) def clickController( self, event ): @@ -2374,6 +2377,8 @@ class MiniEdit( Frame ): # For now, don't allow hosts to be directly linked stags = self.canvas.gettags( self.widgetToItem[ source ] ) dtags = self.canvas.gettags( target ) + # TODO: Make this less confusing + # pylint: disable=too-many-boolean-expressions if (('Host' in stags and 'Host' in dtags) or ('Controller' in dtags and 'LegacyRouter' in stags) or ('Controller' in stags and 'LegacyRouter' in dtags) or @@ -2657,7 +2662,7 @@ class MiniEdit( Frame ): linkopts = {} source.links[ dest ] = self.link dest.links[ source ] = self.link - self.links[ self.link ] = {'type' :linktype, + self.links[ self.link ] = {'type':linktype, 'src':source, 'dest':dest, 'linkOpts':linkopts} @@ -3225,7 +3230,8 @@ class MiniEdit( Frame ): "Parse custom file and add params before parsing cmd-line options." customs = {} if os.path.isfile( fileName ): - execfile( fileName, customs, customs ) + with open( fileName, 'r' ) as f: + exec( f.read() ) # pylint: disable=exec-used for name, val in customs.items(): self.setCustom( name, val ) else: @@ -3592,8 +3598,7 @@ def addDictOption( opts, choicesDict, default, name, helpStr=None ): if __name__ == '__main__': setLogLevel( 'info' ) app = MiniEdit() - ### import topology if specified ### app.parseArgs() + ### import topology if specified ### app.importTopo() - app.mainloop() diff --git a/examples/mobility.py b/examples/mobility.py index d7347da..05a8869 100755 --- a/examples/mobility.py +++ b/examples/mobility.py @@ -19,14 +19,13 @@ to-do: - think about clearing last hop - why doesn't that work? """ +from random import randint from mininet.net import Mininet from mininet.node import OVSSwitch from mininet.topo import LinearTopo from mininet.log import info, output, warn, setLogLevel -from random import randint - class MobilitySwitch( OVSSwitch ): "Switch that can reattach and rename interfaces" @@ -38,6 +37,7 @@ class MobilitySwitch( OVSSwitch ): del self.intfs[ port ] del self.nameToIntf[ intf.name ] + # pylint: disable=arguments-differ def addIntf( self, intf, rename=False, **kwargs ): "Add (and reparent) an interface" OVSSwitch.addIntf( self, intf, **kwargs ) @@ -132,6 +132,7 @@ def mobilityTest(): old = new net.stop() + if __name__ == '__main__': setLogLevel( 'info' ) mobilityTest() diff --git a/examples/multilink.py b/examples/multilink.py index b6b4051..e95730a 100755 --- a/examples/multilink.py +++ b/examples/multilink.py @@ -21,6 +21,7 @@ def runMultiLink(): class simpleMultiLinkTopo( Topo ): "Simple topology with multiple links" + # pylint: disable=arguments-differ def build( self, n, **_kwargs ): h1, h2 = self.addHost( 'h1' ), self.addHost( 'h2' ) s1 = self.addSwitch( 's1' ) @@ -29,6 +30,7 @@ class simpleMultiLinkTopo( Topo ): self.addLink( s1, h1 ) self.addLink( s1, h2 ) + if __name__ == '__main__': setLogLevel( 'info' ) runMultiLink() diff --git a/examples/multiping.py b/examples/multiping.py index fedf462..7d723a4 100755 --- a/examples/multiping.py +++ b/examples/multiping.py @@ -8,14 +8,14 @@ multiple hosts and monitor their output interactively for a period= of time. """ +from select import poll, POLLIN +from time import time from mininet.net import Mininet from mininet.node import Node from mininet.topo import SingleSwitchTopo from mininet.log import info, setLogLevel -from select import poll, POLLIN -from time import time def chunks( l, n ): "Divide list l into chunks of size n - thanks Stackoverflow" @@ -59,7 +59,7 @@ def multiping( netsize, chunksize, seconds): # Start pings for subnet in subnets: ips = [ host.IP() for host in subnet ] - #adding bogus to generate packet loss + # adding bogus to generate packet loss ips.append( '10.0.0.200' ) for host in subnet: startpings( host, ips ) diff --git a/examples/multipoll.py b/examples/multipoll.py index e9998df..13ceaa7 100755 --- a/examples/multipoll.py +++ b/examples/multipoll.py @@ -6,15 +6,15 @@ monitoring them """ +from time import time +from select import poll, POLLIN +from subprocess import Popen, PIPE + 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 -from subprocess import Popen, PIPE - def monitorFiles( outfiles, seconds, timeoutms ): "Monitor set of files and return [(host, line)...]" diff --git a/examples/multitest.py b/examples/multitest.py index 2d68cd4..b208ddf 100755 --- a/examples/multitest.py +++ b/examples/multitest.py @@ -17,6 +17,7 @@ def ifconfigTest( net ): for host in hosts: info( host.cmd( 'ifconfig' ) ) + if __name__ == '__main__': lg.setLogLevel( 'info' ) info( "*** Initializing Mininet and kernel modules\n" ) diff --git a/examples/natnet.py b/examples/natnet.py index bfbc6df..638a437 100755 --- a/examples/natnet.py +++ b/examples/natnet.py @@ -27,6 +27,7 @@ from mininet.util import irange class InternetTopo(Topo): "Single switch connected to n hosts." + # pylint: disable=arguments-differ def build(self, n=2, **_kwargs ): # set up inet switch inetSwitch = self.addSwitch('s0') @@ -62,6 +63,7 @@ def run(): CLI(net) net.stop() + if __name__ == '__main__': setLogLevel('info') run() diff --git a/examples/numberedports.py b/examples/numberedports.py index 1fed0da..0bd1d3e 100755 --- a/examples/numberedports.py +++ b/examples/numberedports.py @@ -75,6 +75,7 @@ def testPortNumbering(): info( '*** Stopping network\n' ) net.stop() + if __name__ == '__main__': setLogLevel( 'info' ) testPortNumbering() diff --git a/examples/popen.py b/examples/popen.py index 4de4d61..94e7b45 100755 --- a/examples/popen.py +++ b/examples/popen.py @@ -28,6 +28,7 @@ def monitorhosts( hosts=5 ): # Done net.stop() + if __name__ == '__main__': setLogLevel( 'info' ) monitorhosts( hosts=5 ) diff --git a/examples/popenpoll.py b/examples/popenpoll.py index 75534c9..7f56ef0 100755 --- a/examples/popenpoll.py +++ b/examples/popenpoll.py @@ -2,13 +2,14 @@ "Monitor multiple hosts using popen()/pmonitor()" +from time import time +from signal import SIGINT + from mininet.net import Mininet from mininet.topo import SingleSwitchTopo from mininet.util import pmonitor from mininet.log import setLogLevel, info -from time import time -from signal import SIGINT def pmonitorTest( N=3, seconds=10 ): "Run pings and monitor multiple hosts using pmonitor" @@ -31,6 +32,7 @@ def pmonitorTest( N=3, seconds=10 ): p.send_signal( SIGINT ) net.stop() + if __name__ == '__main__': setLogLevel( 'info' ) pmonitorTest() diff --git a/examples/scratchnet.py b/examples/scratchnet.py index cc1d19c..a8d536d 100755 --- a/examples/scratchnet.py +++ b/examples/scratchnet.py @@ -8,6 +8,7 @@ but it exposes the configuration details and allows customization. For most tasks, the higher-level API will be preferable. """ +from time import sleep from mininet.net import Mininet from mininet.node import Node @@ -15,7 +16,6 @@ from mininet.link import Link from mininet.log import setLogLevel, info from mininet.util import quietRun -from time import sleep def scratchNet( cname='controller', cargs='-v ptcp:' ): "Create network from scratch using Open vSwitch." @@ -62,6 +62,7 @@ def scratchNet( cname='controller', cargs='-v ptcp:' ): switch.deleteIntfs() info( '\n' ) + if __name__ == '__main__': setLogLevel( 'info' ) info( '*** Scratch network demo (kernel datapath)\n' ) diff --git a/examples/scratchnetuser.py b/examples/scratchnetuser.py index 690c712..2c50f9d 100755 --- a/examples/scratchnetuser.py +++ b/examples/scratchnetuser.py @@ -66,6 +66,7 @@ def scratchNetUser( cname='controller', cargs='ptcp:' ): switch.deleteIntfs() info( '\n' ) + if __name__ == '__main__': setLogLevel( 'info' ) info( '*** Scratch network demo (user datapath)\n' ) diff --git a/examples/simpleperf.py b/examples/simpleperf.py index 0124d79..91e7e01 100755 --- a/examples/simpleperf.py +++ b/examples/simpleperf.py @@ -9,6 +9,7 @@ iperf will hang indefinitely if the TCP handshake fails to complete. """ +from sys import argv from mininet.topo import Topo from mininet.net import Mininet @@ -17,7 +18,6 @@ from mininet.link import TCLink from mininet.util import dumpNodeConnections from mininet.log import setLogLevel, info -from sys import argv # It would be nice if we didn't have to do this: # pylint: disable=arguments-differ @@ -54,6 +54,7 @@ def perfTest( lossy=True ): net.iperf( ( h1, h4 ), l4Type='UDP' ) net.stop() + if __name__ == '__main__': setLogLevel( 'info' ) # Prevent test_simpleperf from failing due to packet loss diff --git a/examples/sshd.py b/examples/sshd.py index a5641ac..ac62fb5 100755 --- a/examples/sshd.py +++ b/examples/sshd.py @@ -47,6 +47,7 @@ def connectToRootNS( network, switch, ip, routes ): for route in routes: root.cmd( 'route add -net ' + route + ' dev ' + str( intf ) ) +# pylint: disable=too-many-arguments def sshd( network, cmd='/usr/sbin/sshd', opts='-D', ip='10.123.123.1/32', routes=None, switch=None ): """Start a network, connect it to root ns, and run sshd on all hosts. @@ -73,6 +74,7 @@ def sshd( network, cmd='/usr/sbin/sshd', opts='-D', host.cmd( 'kill %' + cmd ) network.stop() + if __name__ == '__main__': lg.setLogLevel( 'info') net = TreeNet( depth=1, fanout=4 ) diff --git a/examples/treeping64.py b/examples/treeping64.py index c72943c..1c044b1 100755 --- a/examples/treeping64.py +++ b/examples/treeping64.py @@ -38,6 +38,7 @@ def treePing64(): info( "%s: %d%% packet loss\n" % ( name, results[ name ] ) ) info( '\n' ) + if __name__ == '__main__': setLogLevel( 'info' ) treePing64() diff --git a/examples/vlanhost.py b/examples/vlanhost.py index ec68b93..d15d2d6 100755 --- a/examples/vlanhost.py +++ b/examples/vlanhost.py @@ -24,14 +24,18 @@ Usage (example uses VLAN ID=1000): """ +from sys import exit # pylint: disable=redefined-builtin + from mininet.node import Host from mininet.topo import Topo from mininet.util import quietRun from mininet.log import error + class VLANHost( Host ): "Host connected to VLAN interface" + # pylint: disable=arguments-differ def config( self, vlan=100, **params ): """Configure VLANHost according to (optional) parameters: vlan: VLAN ID for default interface""" @@ -54,6 +58,7 @@ class VLANHost( Host ): return r + hosts = { 'vlan': VLANHost } @@ -101,6 +106,7 @@ def exampleCustomTags(): CLI( net ) net.stop() + if __name__ == '__main__': import sys from functools import partial diff --git a/mininet/cli.py b/mininet/cli.py index 5c644ca..82e2ac5 100644 --- a/mininet/cli.py +++ b/mininet/cli.py @@ -47,7 +47,7 @@ class CLI( Cmd ): prompt = 'mininet> ' def __init__( self, mininet, stdin=sys.stdin, script=None, - *args, **kwargs ): + **kwargs ): """Start and run interactive or batch mode CLI mininet: Mininet network object stdin: standard input for CLI @@ -59,7 +59,7 @@ class CLI( Cmd ): self.inPoller = poll() self.inPoller.register( stdin ) self.inputFile = script - Cmd.__init__( self, *args, stdin=stdin, **kwargs ) + Cmd.__init__( self, stdin=stdin, **kwargs ) info( '*** Starting CLI:\n' ) if self.inputFile: @@ -79,6 +79,7 @@ class CLI( Cmd ): return cls.readlineInited = True try: + # pylint: disable=import-outside-toplevel from readline import ( read_history_file, write_history_file, set_history_length ) except ImportError: @@ -141,7 +142,7 @@ class CLI( Cmd ): ' mininet> xterm h2\n\n' ) - def do_help( self, line ): + def do_help( self, line ): # pylint: disable=arguments-differ "Describe available CLI commands." Cmd.do_help( self, line ) if line == '': @@ -173,6 +174,7 @@ class CLI( Cmd ): """Evaluate a Python expression. Node names may be used, e.g.: py h1.cmd('ls')""" try: + # pylint: disable=eval-used result = eval( line, globals(), self.getLocals() ) if not result: return @@ -467,10 +469,10 @@ class CLI( Cmd ): node.sendInt() except select.error as e: # pylint: disable=unpacking-non-sequence + # pylint: disable=unbalanced-tuple-unpacking errno_, errmsg = e.args - # pylint: enable=unpacking-non-sequence if errno_ != errno.EINTR: - error( "select.error: %d, %s" % (errno_, errmsg) ) + error( "select.error: %s, %s" % (errno_, errmsg) ) node.sendInt() def precmd( self, line ): @@ -488,3 +490,4 @@ def isReadable( poller ): mask = fdmask[ 1 ] if mask & POLLIN: return True + return False diff --git a/mininet/link.py b/mininet/link.py index bf10dc7..56912f7 100644 --- a/mininet/link.py +++ b/mininet/link.py @@ -24,9 +24,14 @@ TCIntf: interface with bandwidth limiting and delay via tc Link: basic link class for creating veth pairs """ +import re + from mininet.log import info, error, debug from mininet.util import makeIntfPair -import re + +# Make pylint happy: +# pylint: disable=too-many-arguments + class Intf( object ): @@ -170,7 +175,7 @@ class Intf( object ): name, value = list( param.items() )[ 0 ] f = getattr( self, method, None ) if not f or value is None: - return + return None if isinstance( value, list ): result = f( *value ) elif isinstance( value, dict ): @@ -311,6 +316,7 @@ class TCIntf( Intf ): debug(" *** executing command: %s\n" % c) return self.cmd( c ) + # pylint: disable=arguments-differ def config( self, bw=None, delay=None, jitter=None, loss=None, gro=False, txo=True, rxo=True, speedup=0, use_hfsc=False, use_tbf=False, @@ -351,7 +357,7 @@ class TCIntf( Intf ): # Question: what happens if we want to reset things? if ( bw is None and not delay and not loss and max_queue_size is None ): - return + return None # Clear existing configuration tcoutput = self.tc( '%s qdisc show dev %s' ) @@ -533,7 +539,11 @@ class OVSLink( Link ): def __init__( self, node1, node2, **kwargs ): "See Link.__init__() for options" - from mininet.node import OVSSwitch + try: + OVSSwitch + except NameError: + # pylint: disable=import-outside-toplevel,cyclic-import + from mininet.node import OVSSwitch self.isPatchLink = False if ( isinstance( node1, OVSSwitch ) and isinstance( node2, OVSSwitch ) ): @@ -541,6 +551,7 @@ class OVSLink( Link ): kwargs.update( cls1=OVSIntf, cls2=OVSIntf ) Link.__init__( self, node1, node2, **kwargs ) + # pylint: disable=arguments-differ, signature-differs def makeIntfPair( self, *args, **kwargs ): "Usually delegated to OVSSwitch" if self.isPatchLink: diff --git a/mininet/log.py b/mininet/log.py index a19970f..48475e7 100644 --- a/mininet/log.py +++ b/mininet/log.py @@ -20,7 +20,7 @@ LEVELS = { 'debug': logging.DEBUG, # change this to logging.INFO to get printouts when running unit tests LOGLEVELDEFAULT = OUTPUT -#default: '%(asctime)s - %(name)s - %(levelname)s - %(message)s' +# default: '%(asctime)s - %(name)s - %(levelname)s - %(message)s' LOGMSGFORMAT = '%(message)s' @@ -51,7 +51,7 @@ class StreamHandlerNoNewline( logging.StreamHandler ): self.flush() except ( KeyboardInterrupt, SystemExit ): raise - except: + except: # noqa pylint: disable=bare-except self.handleError( record ) @@ -137,13 +137,14 @@ class MininetLogger( Logger, object ): logger.warning("Houston, we have a %s", "cli output", exc_info=1) """ - if self.manager.disable >= OUTPUT: + if getattr( self.manager, 'disabled', 0 ) >= OUTPUT: return if self.isEnabledFor( OUTPUT ): self._log( OUTPUT, msg, args, kwargs ) # pylint: enable=method-hidden + lg = MininetLogger() # Make things a bit more convenient by adding aliases @@ -168,6 +169,7 @@ def makeListCompatible( fn ): setattr( newfn, '__doc__', fn.__doc__ ) return newfn + _loggers = lg.info, lg.output, lg.warn, lg.error, lg.debug _loggers = tuple( makeListCompatible( logger ) for logger in _loggers ) diff --git a/mininet/moduledeps.py b/mininet/moduledeps.py index fda2d70..470465a 100644 --- a/mininet/moduledeps.py +++ b/mininet/moduledeps.py @@ -1,8 +1,11 @@ "Module dependency utility functions for Mininet." +from os import environ +from sys import exit # pylint: disable=redefined-builtin + from mininet.util import quietRun, BaseString from mininet.log import info, error, debug -from os import environ + def lsmod(): "Return output of lsmod." @@ -18,6 +21,7 @@ def modprobe( mod ): mod: module string""" return quietRun( [ 'modprobe', mod ] ) + OF_KMOD = 'ofdatapath' OVS_KMOD = 'openvswitch_mod' # Renamed 'openvswitch' in OVS 1.7+/Linux 3.5+ TUN = 'tun' diff --git a/mininet/net.py b/mininet/net.py index 84bb7ae..8bca10e 100755 --- a/mininet/net.py +++ b/mininet/net.py @@ -92,6 +92,7 @@ import select import signal import random +from sys import exit # pylint: disable=redefined-builtin from time import sleep from itertools import chain, groupby from math import ceil @@ -113,6 +114,7 @@ VERSION = "2.3.0a1" class Mininet( object ): "Network emulation with hosts spawned in network namespaces." + # pylint: disable=too-many-arguments def __init__( self, topo=None, switch=OVSKernelSwitch, host=Host, controller=DefaultController, link=Link, intf=Intf, build=True, xterms=False, cleanup=False, ipBase='10.0.0.0/8', diff --git a/mininet/node.py b/mininet/node.py index c3e12a7..817b39a 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -57,7 +57,10 @@ import pty import re import signal import select +from distutils.version import StrictVersion +from re import findall from subprocess import Popen, PIPE +from sys import exit # pylint: disable=redefined-builtin from time import sleep from mininet.log import info, error, warn, debug @@ -66,8 +69,10 @@ from mininet.util import ( quietRun, errRun, errFail, moveIntf, isShellBuiltin, encode, getincrementaldecoder, Python3, which ) from mininet.moduledeps import moduleDeps, pathCheck, TUN from mininet.link import Link, Intf, TCIntf, OVSIntf -from re import findall -from distutils.version import StrictVersion + + +# pylint: disable=too-many-arguments + class Node( object ): """A virtual network node is simply a shell in a network namespace. @@ -94,9 +99,13 @@ class Node( object ): # Stash configuration parameters for future reference self.params = params - self.intfs = {} # dict of port numbers to interfaces - self.ports = {} # dict of interfaces to port numbers - # replace with Port objects, eventually ? + # dict of port numbers to interfacse + self.intfs = {} + + # dict of interfaces to port numbers + # todo: replace with Port objects, eventually ? + self.ports = {} + self.nameToIntf = {} # dict of interface names to Intfs # Make pylint happy @@ -284,6 +293,7 @@ class Node( object ): returns: result of poll()""" if len( self.readbuf ) == 0: return self.pollOut.poll( timeoutms ) + return None def sendCmd( self, *args, **kwargs ): """Send a command, followed by a command to echo a sentinel, @@ -377,6 +387,7 @@ class Node( object ): return self.waitOutput( verbose ) else: warn( '(%s exited - ignoring cmd%s)\n' % ( self, args ) ) + return None def cmdPrint( self, *args): """Call cmd and printing its output @@ -469,6 +480,7 @@ class Node( object ): else: warn( '*** defaultIntf: warning:', self.name, 'has no interfaces\n' ) + return None def intf( self, intf=None ): """Return our interface object with given string name, @@ -582,10 +594,10 @@ class Node( object ): value may also be list or dict""" name, value = list( param.items() )[ 0 ] if value is None: - return + return None f = getattr( self, method, None ) if not f: - return + return None if isinstance( value, list ): result = f( *value ) elif isinstance( value, dict ): @@ -653,11 +665,12 @@ class Node( object ): @classmethod def checkSetup( cls ): "Make sure our class and superclasses are set up" - while cls and not getattr( cls, 'isSetup', True ): - cls.setup() - cls.isSetup = True + clas = cls + while clas and not getattr( clas, 'isSetup', True ): + clas.setup() + clas.isSetup = True # Make pylint happy - cls = getattr( type( cls ), '__base__', None ) + clas = getattr( type( clas ), '__base__', None ) @classmethod def setup( cls ): @@ -838,6 +851,7 @@ class CPULimitedHost( Host ): errFail( 'cgclassify -g cpuset:/%s %s' % ( self.name, self.pid ) ) + # pylint: disable=arguments-differ def config( self, cpu=-1, cores=None, **params ): """cpu: desired overall system CPU fraction cores: (real) core(s) this host can run on @@ -930,6 +944,7 @@ class Switch( Node ): else: error( '*** Error: %s has execed and cannot accept commands' % self.name ) + return None def connected( self ): "Is the switch connected to a controller? (override this method)" @@ -1115,6 +1130,7 @@ class OVSSwitch( Switch ): if self.batch: cmd = ' '.join( str( arg ).strip() for arg in args ) self.commands.append( cmd ) + return None else: return self.cmd( 'ovs-vsctl', *args, **kwargs ) @@ -1302,7 +1318,7 @@ class OVSBridge( OVSSwitch ): "Are we forwarding yet?" if self.stp: status = self.dpctl( 'show' ) - return 'STP_FORWARD' in status and not 'STP_LEARN' in status + return 'STP_FORWARD' in status and 'STP_LEARN' not in status else: return True @@ -1429,6 +1445,7 @@ class Controller( Node ): ' 1>' + cout + ' 2>' + cout + ' &' ) self.execed = False + # pylint: disable=arguments-differ,signature-differs def stop( self, *args, **kwargs ): "Stop controller." self.cmd( 'kill %' + self.command ) @@ -1479,7 +1496,7 @@ class NOX( Controller ): warn( 'warning: no NOX modules specified; ' 'running packetdump only\n' ) noxArgs = [ 'packetdump' ] - elif type( noxArgs ) not in ( list, tuple ): + elif not isinstance( noxArgs, ( list, tuple ) ): noxArgs = [ noxArgs ] if 'NOX_CORE_DIR' not in os.environ: @@ -1505,7 +1522,7 @@ class Ryu( Controller ): warn( 'warning: no Ryu modules specified; ' 'running simple_switch only\n' ) ryuArgs = [ ryuCoreDir + 'simple_switch.py' ] - elif type( ryuArgs ) not in ( list, tuple ): + elif not isinstance( ryuArgs, ( list, tuple ) ): ryuArgs = [ ryuArgs ] Controller.__init__( self, name, @@ -1532,6 +1549,7 @@ class RemoteController( Controller ): "Overridden to do nothing." return + # pylint: disable=arguments-differ def stop( self ): "Overridden to do nothing." return @@ -1563,6 +1581,7 @@ class RemoteController( Controller ): else: return True + DefaultControllers = ( Controller, OVSController ) def findController( controllers=DefaultControllers ): @@ -1570,6 +1589,7 @@ def findController( controllers=DefaultControllers ): for controller in controllers: if controller.isAvailable(): return controller + return None def DefaultController( name, controllers=DefaultControllers, **kwargs ): "Find a controller that is available and instantiate it" diff --git a/mininet/nodelib.py b/mininet/nodelib.py index 1d5106e..44ee6d0 100644 --- a/mininet/nodelib.py +++ b/mininet/nodelib.py @@ -102,6 +102,7 @@ class NAT( Node ): # hopefully this won't disconnect you self.cmd( 'service network-manager restart || netplan apply' ) + # pylint: disable=arguments-differ def config( self, **params ): """Configure the NAT and iptables""" diff --git a/mininet/term.py b/mininet/term.py index 04d9871..769367d 100644 --- a/mininet/term.py +++ b/mininet/term.py @@ -50,7 +50,7 @@ def makeTerm( node, title='Node', term='xterm', display=None, cmd='bash'): } if term not in cmds: error( 'invalid terminal type: %s' % term ) - return + return None display, tunnel = tunnelX11( node, display ) if display is None: return [] diff --git a/mininet/test/runner.py b/mininet/test/runner.py index 73dd9fb..4540599 100755 --- a/mininet/test/runner.py +++ b/mininet/test/runner.py @@ -25,6 +25,7 @@ def runTests( testDir, verbosity=1 ): .run( testSuite ).wasSuccessful() ) sys.exit( 0 if success else 1 ) + if __name__ == '__main__': setLogLevel( 'warning' ) # get the directory containing example tests diff --git a/mininet/test/test_hifi.py b/mininet/test/test_hifi.py index 1a3a0ac..ec74239 100755 --- a/mininet/test/test_hifi.py +++ b/mininet/test/test_hifi.py @@ -45,7 +45,7 @@ class testOptionsTopoCommon( object ): @staticmethod def tearDown(): "Clean up if necessary" - if sys.exc_info != ( None, None, None ): + if sys.exc_info() != ( None, None, None ): cleanup() def runOptionsTopoTest( self, n, msg, hopts=None, lopts=None ): @@ -95,7 +95,7 @@ class testOptionsTopoCommon( object ): CPU_FRACTION = 0.1 CPU_TOLERANCE = 0.8 # CPU fraction below which test should fail hopts = { 'cpu': CPU_FRACTION } - #self.runOptionsTopoTest( N, hopts=hopts ) + # self.runOptionsTopoTest( N, hopts=hopts ) mn = Mininet( SingleSwitchOptionsTopo( n=N, hopts=hopts ), host=CPULimitedHost, switch=self.switchClass, @@ -118,7 +118,7 @@ class testOptionsTopoCommon( object ): % ( CPU_FRACTION * 100, hostUsage, N, hoptsStr, self.switchClass ) ) for pct in results: - #divide cpu by 100 to convert from percentage to fraction + # divide cpu by 100 to convert from percentage to fraction self.assertWithinTolerance( pct/100, CPU_FRACTION, CPU_TOLERANCE, msg ) @@ -263,6 +263,7 @@ class testOptionsTopoUserspace( testOptionsTopoCommon, unittest.TestCase ): longMessage = True switchClass = UserSwitch + if __name__ == '__main__': setLogLevel( 'warning' ) unittest.main() diff --git a/mininet/test/test_nets.py b/mininet/test/test_nets.py index e468555..98048ec 100755 --- a/mininet/test/test_nets.py +++ b/mininet/test/test_nets.py @@ -26,7 +26,7 @@ class testSingleSwitchCommon( object ): @staticmethod def tearDown(): "Clean up if necessary" - if sys.exc_info != ( None, None, None ): + if sys.exc_info() != ( None, None, None ): cleanup() def testMinimal( self ): diff --git a/mininet/test/test_ptyleak.py b/mininet/test/test_ptyleak.py index 9d3aafb..813be76 100755 --- a/mininet/test/test_ptyleak.py +++ b/mininet/test/test_ptyleak.py @@ -26,6 +26,7 @@ class TestPtyLeak( unittest.TestCase ): assert ( host.slave, host.master ) == oldptys net.stop() + if __name__ == '__main__': unittest.main() cleanup() diff --git a/mininet/test/test_switchdpidassignment.py b/mininet/test/test_switchdpidassignment.py index 62ef493..f3ea309 100755 --- a/mininet/test/test_switchdpidassignment.py +++ b/mininet/test/test_switchdpidassignment.py @@ -24,7 +24,7 @@ class TestSwitchDpidAssignmentOVS( unittest.TestCase ): "Clean up if necessary" # satisfy pylint assert self - if sys.exc_info != ( None, None, None ): + if sys.exc_info() != ( None, None, None ): cleanup() def testDefaultDpid( self ): @@ -95,6 +95,7 @@ class testSwitchUserspace( TestSwitchDpidAssignmentOVS ): "Test dpid assignment of Userspace switch." switchClass = UserSwitch + if __name__ == '__main__': setLogLevel( 'warning' ) unittest.main() diff --git a/mininet/test/test_util.py b/mininet/test/test_util.py index 66a3128..5e480b7 100755 --- a/mininet/test/test_util.py +++ b/mininet/test/test_util.py @@ -35,5 +35,6 @@ class testQuietRun( unittest.TestCase ): output = quietRun(testQuietRun.getEchoCmd( n ) ) self.assertEqual( n, len( output ) ) + if __name__ == "__main__": unittest.main() diff --git a/mininet/test/test_walkthrough.py b/mininet/test/test_walkthrough.py index 2b26e18..7ed67fe 100755 --- a/mininet/test/test_walkthrough.py +++ b/mininet/test/test_walkthrough.py @@ -6,14 +6,16 @@ Tests for the Mininet Walkthrough TODO: missing xterm test """ -import unittest import os import re -from mininet.util import quietRun, pexpect -from mininet.clean import cleanup +import unittest + from distutils.version import StrictVersion from sys import stdout +from mininet.util import quietRun, pexpect +from mininet.clean import cleanup + def tsharkVersion(): "Return tshark version" @@ -74,7 +76,7 @@ class testWalkthrough( unittest.TestCase ): p.expect( self.prompt ) # net command p.sendline( 'net' ) - expected = [ x for x in nodes ] + expected = list( nodes ) while len( expected ) > 0: index = p.expect( expected ) node = p.match.group( 0 ) @@ -110,7 +112,7 @@ class testWalkthrough( unittest.TestCase ): ifcount = 0 while True: index = p.expect( interfaces ) - if index == 0 or index == 3: + if index in (0, 3): ifcount += 1 elif index == 1: self.fail( 's1 interface displayed in "h1 ifconfig"' ) @@ -126,7 +128,7 @@ class testWalkthrough( unittest.TestCase ): index = p.expect( interfaces ) if index == 0: self.fail( 'h1 interface displayed in "s1 ifconfig"' ) - elif index == 1 or index == 2 or index == 3: + elif index in (1, 2, 3): ifcount += 1 else: break @@ -309,7 +311,7 @@ class testWalkthrough( unittest.TestCase ): ifcount = 0 while True: index = p.expect( interfaces ) - if index == 1 or index == 3: + if index in (1, 3): ifcount += 1 elif index == 0: self.fail( 'h1 interface displayed in "s1 ifconfig"' ) diff --git a/mininet/topo.py b/mininet/topo.py index d3cb67f..21f1dcf 100644 --- a/mininet/topo.py +++ b/mininet/topo.py @@ -13,6 +13,9 @@ setup for testing, and can even be emulated with the Mininet package. from mininet.util import irange, natural, naturalSeq +# pylint: disable=too-many-arguments + + class MultiGraph( object ): "Utility class to track nodes and edges - replaces networkx.MultiGraph" diff --git a/mininet/util.py b/mininet/util.py index d724096..36b5d24 100644 --- a/mininet/util.py +++ b/mininet/util.py @@ -1,19 +1,23 @@ "Utility functions for Mininet." +import codecs +import os +import re +import sys -from mininet.log import output, info, error, warn, debug - -from time import sleep +from fcntl import fcntl, F_GETFL, F_SETFL +from functools import partial +from os import O_NONBLOCK from resource import getrlimit, setrlimit, RLIMIT_NPROC, RLIMIT_NOFILE from select import poll, POLLIN, POLLHUP from subprocess import call, check_call, Popen, PIPE, STDOUT -import re -from fcntl import fcntl, F_GETFL, F_SETFL -from os import O_NONBLOCK -import os -from functools import partial -import sys -import codecs +from sys import exit # pylint: disable=redefined-builtin +from time import sleep + +from mininet.log import output, info, error, warn, debug + +# pylint: disable=too-many-arguments + # Python 2/3 compatibility @@ -454,6 +458,7 @@ def pmonitor(popens, timeoutms=500, readline=True, poller.register( fd, POLLIN ) flags = fcntl( fd, F_GETFL ) fcntl( fd, F_SETFL, flags | O_NONBLOCK ) + # pylint: disable=too-many-nested-blocks while popens: fds = poller.poll( timeoutms ) if fds: @@ -665,7 +670,6 @@ def ensureRoot(): if os.getuid() != 0: error( '*** Mininet must run as root.\n' ) exit( 1 ) - return def waitListening( client=None, server='127.0.0.1', port=80, timeout=None ): """Wait until server is listening on port.