f0c726a42f
This helps with virtualenv although it can open up another security hole if you end up using an unexpected python interpreter. Overall it seems to make sense to err on the side of usability but it's good to be aware of security. However, for the remaining utility scripts that require python 2, we explicitly note this with #!/usr/bin/python2.
108 lines
4.2 KiB
Python
108 lines
4.2 KiB
Python
#!/usr/bin/env python
|
|
|
|
"CLI for Mininet Cluster Edition prototype demo"
|
|
|
|
from mininet.cli import CLI
|
|
from mininet.log import output, error
|
|
|
|
# pylint: disable=global-statement
|
|
nx, graphviz_layout, plt = None, None, None # Will be imported on demand
|
|
|
|
|
|
class ClusterCLI( CLI ):
|
|
"CLI with additional commands for Cluster Edition demo"
|
|
|
|
@staticmethod
|
|
def colorsFor( seq ):
|
|
"Return a list of background colors for a sequence"
|
|
colors = [ 'red', 'lightgreen', 'cyan', 'yellow', 'orange',
|
|
'magenta', 'pink', 'grey', 'brown',
|
|
'white' ]
|
|
slen, clen = len( seq ), len( colors )
|
|
reps = max( 1, slen / clen )
|
|
colors = colors * reps
|
|
colors = colors[ 0 : slen ]
|
|
return colors
|
|
|
|
def do_plot( self, _line ):
|
|
"Plot topology colored by node placement"
|
|
# Import networkx if needed
|
|
global nx, plt, graphviz_layout
|
|
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
|
|
plt = pyplot # satisfy pylint
|
|
import pygraphviz
|
|
assert pygraphviz # silence pyflakes
|
|
# Networkx moved this around
|
|
if hasattr( nx, 'graphviz_layout' ):
|
|
graphviz_layout = nx.graphviz_layout
|
|
else:
|
|
graphviz_layout = nx.drawing.nx_agraph.graphviz_layout
|
|
# pylint: enable=import-error,no-member
|
|
except ImportError:
|
|
error( 'plot requires networkx, matplotlib and pygraphviz - '
|
|
'please install them and try again\n' )
|
|
return
|
|
# Make a networkx Graph
|
|
g = nx.Graph()
|
|
mn = self.mn
|
|
servers = getattr( mn, 'servers', [ 'localhost' ] )
|
|
hosts, switches = mn.hosts, mn.switches
|
|
nodes = hosts + switches
|
|
g.add_nodes_from( nodes )
|
|
links = [ ( link.intf1.node, link.intf2.node )
|
|
for link in self.mn.links ]
|
|
g.add_edges_from( links )
|
|
# Pick some shapes and colors
|
|
# shapes = hlen * [ 's' ] + slen * [ 'o' ]
|
|
color = dict( zip( servers, self.colorsFor( servers ) ) )
|
|
# Plot it!
|
|
pos = graphviz_layout( g )
|
|
opts = { 'ax': None, 'font_weight': 'bold',
|
|
'width': 2, 'edge_color': 'darkblue' }
|
|
hcolors = [ color[ getattr( h, 'server', 'localhost' ) ]
|
|
for h in hosts ]
|
|
scolors = [ color[ getattr( s, 'server', 'localhost' ) ]
|
|
for s in switches ]
|
|
nx.draw_networkx( g, pos=pos, nodelist=hosts, node_size=800,
|
|
label='host', node_color=hcolors, node_shape='s',
|
|
**opts )
|
|
nx.draw_networkx( g, pos=pos, nodelist=switches, node_size=1000,
|
|
node_color=scolors, node_shape='o', **opts )
|
|
# Get rid of axes, add title, and show
|
|
fig = plt.gcf()
|
|
ax = plt.gca()
|
|
ax.get_xaxis().set_visible( False )
|
|
ax.get_yaxis().set_visible( False )
|
|
fig.canvas.set_window_title( 'Mininet')
|
|
plt.title( 'Node Placement', fontweight='bold' )
|
|
plt.show()
|
|
|
|
def do_status( self, _line ):
|
|
"Report on node shell status"
|
|
nodes = self.mn.hosts + self.mn.switches
|
|
for node in nodes:
|
|
node.shell.poll()
|
|
exited = [ node for node in nodes
|
|
if node.shell.returncode is not None ]
|
|
if exited:
|
|
for node in exited:
|
|
output( '%s has exited with code %d\n'
|
|
% ( node, node.shell.returncode ) )
|
|
else:
|
|
output( 'All nodes are still running.\n' )
|
|
|
|
def do_placement( self, _line ):
|
|
"Describe node placement"
|
|
mn = self.mn
|
|
nodes = mn.hosts + mn.switches + mn.controllers
|
|
for server in mn.servers:
|
|
names = [ n.name for n in nodes if hasattr( n, 'server' )
|
|
and n.server == server ]
|
|
output( '%s: %s\n' % ( server, ' '.join( names ) ) )
|