Statistics
| Branch: | Tag: | Revision:

mininet / examples / consoles.py @ d0e53ca8

History | View | Annotate | Download (5.44 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
Tkinter's createfilehandler() and Node()'s monitor().
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

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

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

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

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

    
95
    def handleReadable( self, file, mask ):
96
        data = self.node.monitor()
97
        self.append( data )
98
        if not self.node.waiting:
99
            # Print prompt, just for the heck of it
100
            self.append( self.prompt )
101

    
102
class ConsoleApp( Frame ):
103

    
104
    def __init__( self, net, nodes, parent=None, width=4 ):
105
        Frame.__init__( self, parent )
106
        self.top = self.winfo_toplevel()
107
        self.top.title( 'Mininet' )
108
        self.net = net
109
        self.nodes = nodes
110
        self.createMenuBar( font='Geneva 7' )
111
        self.consoles = self.createConsoles( nodes, width )
112
        self.pack( expand=True, fill='both' )
113
        cleanUpScreens()
114
        
115
    def createConsoles( self, nodes, width ):
116
        "Create a grid of consoles in a frame."
117
        f = Frame( self )
118
        # Create consoles
119
        consoles = []
120
        index = 0
121
        for node in nodes:
122
            console = Console( f, net, node )
123
            consoles.append( console )
124
            row = int( index / width )
125
            column = index % width
126
            console.grid( row=row, column=column, sticky='nsew' )
127
            index += 1
128
            f.rowconfigure( row, weight=1 )
129
            f.columnconfigure( column, weight=1 )
130
        f.pack( expand=True, fill='both' )
131
        return consoles
132
        
133
    def createMenuBar( self, font ):
134
        "Create and return a menu (really button) bar."
135
        f = Frame( self )
136
        buttons = [
137
            ( 'Ping', self.ping ),
138
            ( 'Interrupt', self.stop ),
139
            ( 'Quit', self.quit )
140
        ]
141
        for name, cmd in buttons:
142
            b = Button( f, text=name, command=cmd, font=font )
143
            b.pack( side='left' )
144
        f.pack( padx=4, pady=4, fill='x' )
145
        return f
146
    
147
    def ping( self ):
148
        "Tell each console to ping the next one."
149
        consoles = self.consoles
150
        count = len( consoles )
151
        i = 0
152
        for console in consoles:
153
            i = ( i + 1 ) % count
154
            ip = consoles[ i ].node.IP()
155
            console.sendCmd( 'ping ' + ip )
156
            
157
    def stop( self ):
158
        "Interrupt all consoles."
159
        for console in self.consoles:
160
            console.handleInt()
161

    
162
    
163
if __name__ == '__main__':
164
    setLogLevel( 'info' )
165
    net = TreeNet( depth=2, fanout=4 )
166
    net.start()
167
    app = ConsoleApp( net, net.hosts, width=4 )
168
    app.mainloop()
169
    net.stop()