Statistics
| Branch: | Tag: | Revision:

mininet / examples / consoles.py @ c3a583c8

History | View | Annotate | Download (6.78 KB)

1
#!/usr/bin/python
2

    
3
"""
4
consoles.py: bring up a bunch of miniature consoles on a virtual network
5

6
This demo shows how to monitor a set of nodes by using
7
Node's monitor() and Tkinter's createfilehandler().
8
"""
9

    
10
from Tkinter import *
11

    
12
from mininet.log import setLogLevel
13
from mininet.topolib import TreeNet
14
from mininet.term import makeTerms, cleanUpScreens
15
from mininet.util import quietRun
16

    
17
class Console( Frame ):
18
    "A simple console on a host."
19
    
20
    def __init__( self, parent, net, node, height=10, width=32 ):
21
        Frame.__init__( self, parent )
22
        self.net = net
23
        self.node = node
24
        self.prompt = node.name + '# '
25
        self.height, self.width = height, width
26
        self.text = self.makeWidgets( )
27
        self.bindEvents()
28
        self.append( self.prompt )
29

    
30
    def makeWidgets( self ):
31
        "Make a label, a text area, and a scroll bar."
32
        buttonStyle = {
33
            'font': 'Monaco 7',
34
        }
35
        textStyle = { 
36
            'font': 'Monaco 7',
37
            'bg': 'black',
38
            'fg': 'green',
39
            'width': self.width,
40
            'height': self.height,
41
            'relief': 'sunken',
42
            'insertbackground': 'green',
43
            'highlightcolor': 'green',
44
            'selectforeground': 'black',
45
            'selectbackground': 'green'
46
        }
47
        def newTerm( net=self.net, node=self.node ):
48
            "Pop up a new terminal window for a node."
49
            net.terms += makeTerms( [ node ] )
50
        label = Button( self, text=self.node.name, command=newTerm, **buttonStyle )
51
        label.pack( side='top', fill='x' )
52
        text = Text( self, wrap='word', **textStyle )
53
        ybar = Scrollbar( self, orient='vertical', width=7, command=text.yview )
54
        text.configure( yscrollcommand=ybar.set )
55
        text.pack( side='left', expand=True, fill='both' )
56
        ybar.pack( side='right', fill='y' )
57
        return text
58

    
59
    def bindEvents( self ):
60
        "Bind keyboard and file events."
61
        self.text.bind( '<Return>', self.handleReturn )
62
        self.text.bind( '<Control-c>', self.handleInt )
63
        # self.text.bind( '<KeyPress>', self.handleKey )
64
        # This is not well-documented, but it is the correct
65
        # way to trigger a file event handler from Tk's
66
        # event loop!
67
        self.tk.createfilehandler( self.node.stdout, READABLE,
68
            self.handleReadable )
69

    
70
    def append( self, text ):
71
        "Append something to our text frame."
72
        self.text.insert( 'end', text )
73
        self.text.mark_set( 'insert', 'end' )
74
        self.text.see( 'insert' )
75
    
76
    def handleKey( self, event  ):
77
        "Handle a regular key press."
78
        self.append( event.char )
79
    
80
    def handleReturn( self, event ):
81
        "Handle a carriage return."
82
        cmd = self.text.get( 'insert linestart', 'insert lineend' )
83
        if cmd.find( self.prompt ) == 0:
84
            cmd = cmd[ len( self.prompt ): ]
85
        self.sendCmd( cmd )
86
        
87
    def handleInt( self, event=None ):
88
        "Handle control-c."
89
        self.node.sendInt()
90

    
91
    def sendCmd( self, cmd ):
92
        "Send a command to our node."
93
        text, node = self.text, self.node
94
        if not node.waiting:
95
            node.sendCmd( cmd )
96

    
97
    def handleReadable( self, file=None, mask=None ):
98
        "Handle file readable event."
99
        data = self.node.monitor()
100
        self.append( data )
101
        if not self.node.waiting:
102
            # Print prompt, just for the heck of it
103
            self.append( self.prompt )
104
            
105
    def waitOutput( self ):
106
        "Wait for any remaining output."
107
        while self.node.waiting:
108
            self.handleReadable( self )
109

    
110
    def clear( self ):
111
        "Clear all of our text."
112
        self.text.delete( '1.0', 'end' )
113
        
114
class ConsoleApp( Frame ):
115

    
116
    def __init__( self, net, nodes, parent=None, width=4 ):
117
        Frame.__init__( self, parent )
118
        self.top = self.winfo_toplevel()
119
        self.top.title( 'Mininet' )
120
        self.net = net
121
        self.nodes = nodes
122
        self.createMenuBar( font='Geneva 7' )
123
        self.consoles = self.createConsoles( nodes, width )
124
        self.pack( expand=True, fill='both' )
125
        cleanUpScreens()
126
        # Close window gracefully
127
        Wm.wm_protocol( self.top, name='WM_DELETE_WINDOW', func=self.quit )
128
        
129
    def createConsoles( self, nodes, width ):
130
        "Create a grid of consoles in a frame."
131
        f = Frame( self )
132
        # Create consoles
133
        consoles = []
134
        index = 0
135
        for node in nodes:
136
            console = Console( f, net, node )
137
            consoles.append( console )
138
            row = int( index / width )
139
            column = index % width
140
            console.grid( row=row, column=column, sticky='nsew' )
141
            index += 1
142
            f.rowconfigure( row, weight=1 )
143
            f.columnconfigure( column, weight=1 )
144
        f.pack( expand=True, fill='both' )
145
        return consoles
146
        
147
    def createMenuBar( self, font ):
148
        "Create and return a menu (really button) bar."
149
        f = Frame( self )
150
        buttons = [
151
            ( 'Ping', self.ping ),
152
            ( 'Iperf', self.iperf ),
153
            ( 'Interrupt', self.stop ),
154
            ( 'Clear', self.clear ),
155
            ( 'Quit', self.quit )
156
        ]
157
        for name, cmd in buttons:
158
            b = Button( f, text=name, command=cmd, font=font )
159
            b.pack( side='left' )
160
        f.pack( padx=4, pady=4, fill='x' )
161
        return f
162
    
163
    def clear( self ):
164
        "Clear all consoles."
165
        for console in self.consoles:
166
            console.clear()
167
            
168
    def ping( self ):
169
        "Tell each console to ping the next one."
170
        consoles = self.consoles
171
        count = len( consoles )
172
        i = 0
173
        for console in consoles:
174
            i = ( i + 1 ) % count
175
            ip = consoles[ i ].node.IP()
176
            console.sendCmd( 'ping ' + ip )
177

    
178
    def iperf( self ):
179
        "Tell each console to iperf to the next one."
180
        consoles = self.consoles
181
        count = len( consoles )
182
        for console in consoles:
183
            console.node.cmd( 'iperf -sD' )
184
        i = 0
185
        for console in consoles:
186
            i = ( i + 1 ) % count
187
            ip = consoles[ i ].node.IP()
188
            console.sendCmd( 'iperf -t 99999 -i 1 -c ' + ip )
189

    
190
    def stop( self ):
191
        "Interrupt all consoles."
192
        for console in self.consoles:
193
            console.handleInt()
194
        for console in self.consoles:
195
            console.waitOutput()
196
        # Shut down any iperfs that might still be running
197
        quietRun( 'killall -9 iperf' )
198

    
199
    def quit( self ):
200
        "Stope everything and quit."
201
        print "Quit"
202
        self.stop()
203
        Frame.quit( self )
204

    
205
if __name__ == '__main__':
206
    setLogLevel( 'info' )
207
    net = TreeNet( depth=2, fanout=4 )
208
    net.start()
209
    app = ConsoleApp( net, net.hosts, width=4 )
210
    app.mainloop()
211
    net.stop()