Revision afe0ce81

View differences:

examples/consoles.py
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

  
15
class Console( Frame ):
16
    "A simple console on a host."
17
    
18
    def __init__( self, parent, node, height=16, width=32 ):
19
        Frame.__init__( self, parent )
20
        self.node = node
21
        self.height, self.width = height, width
22
        self.text = self.makeWidgets( )
23
        self.bindEvents()
24

  
25
    def makeWidgets( self ):
26
        "Make a label, a text area, and a scroll bar."
27
        labelStyle = {
28
            'font': 'Monaco 7',
29
            'relief': 'sunken'
30
        }
31
        textStyle = { 
32
            'font': 'Monaco 7',
33
            'bg': 'black',
34
            'fg': 'green',
35
            'width': self.width,
36
            'height': self.height,
37
            'relief': 'sunken'
38
        }
39
        label = Label( self, text=self.node.name, **labelStyle )
40
        label.pack( side='top', fill='x' )
41
        text = Text( self, wrap='word', **textStyle )
42
        ybar = Scrollbar( self, orient='vertical', command=text.yview )
43
        text.configure( yscrollcommand=ybar.set )
44
        text.pack( side='left', expand=True, fill='both' )
45
        ybar.pack( side='right', fill='y' )
46
        return text
47

  
48
    def bindEvents( self ):
49
        "Bind keyboard and file events."
50
        self.text.bind( '<Return>', self.handleReturn )
51
        self.text.bind( '<Control-c>', self.handleInt )
52
        self.text.bind( '<KeyPress>', self.handleKey )
53
        # This is not well-documented, but it is the correct
54
        # way to trigger a file event handler from Tk's
55
        # event loop!
56
        self.tk.createfilehandler( self.node.stdout, READABLE,
57
            self.handleReadable )
58

  
59
    def append( self, text ):
60
        "Append something to our text frame."
61
        self.text.insert( 'end', text )
62
        self.text.mark_set( 'insert', 'end' )
63
        self.text.see( 'insert' )
64
    
65
    def handleKey( self, event  ):
66
        "Handle a regular key press."
67
        self.append( event.char )
68
    
69
    def handleReturn( self, event ):
70
        "Handle a carriage return."
71
        print "handleReturn"
72
    
73
    def handleInt( self, event=None ):
74
        "Handle control-c."
75
        self.node.sendInt()
76
        
77
    def sendCmd( self, cmd ):
78
        "Send a command to our node."
79
        text, node = self.text, self.node
80
        node.sendCmd( cmd )
81

  
82
    def handleReadable( self, file, mask ):
83
        data = self.node.monitor()
84
        self.append( data )
85

  
86
class Consoles( Frame ):
87

  
88
    def __init__( self, nodes, parent=None, width=4 ):
89
        Frame.__init__( self, parent )
90
        self.nodes = nodes
91
        self.createMenuBar( font='Geneva 7' )
92
        self.consoles = self.createConsoles( nodes, width )
93
        self.pack( expand=True, fill='both' )
94
        
95
    def createConsoles( self, nodes, width ):
96
        "Create a grid of consoles in a frame."
97
        f = Frame( self )
98
        # Create consoles
99
        consoles = []
100
        index = 0
101
        for node in nodes:
102
            console = Console( f, node )
103
            consoles.append( console )
104
            row = int( index / width )
105
            column = index % width
106
            console.grid( row=row, column=column, sticky='nsew' )
107
            index += 1
108
            f.rowconfigure( row, weight=1 )
109
            f.columnconfigure( column, weight=1 )
110
        f.pack( expand=True, fill='both' )
111
        return consoles
112
        
113
    def createMenuBar( self, font ):
114
        "Create and return a menu (really button) bar."
115
        f = Frame( self )
116
        buttons = [
117
            ( 'Ping', self.ping ),
118
            ( 'Interrupt', self.stop ),
119
            ( 'Quit', self.quit )
120
        ]
121
        for name, cmd in buttons:
122
            b = Button( f, text=name, command=cmd, font=font )
123
            b.pack( side='left' )
124
        f.pack( padx=4, pady=4, fill='x' )
125
        return f
126
    
127
    def ping( self ):
128
        "Tell each console to ping the next one."
129
        consoles = self.consoles
130
        count = len( consoles )
131
        i = 1
132
        for console in consoles:
133
            ip = consoles[ i ].node.IP()
134
            console.sendCmd( 'ping ' + ip )
135
            i = ( i + 1 ) % count
136
            
137
    def stop( self ):
138
        "Interrupt all consoles."
139
        for console in self.consoles:
140
            console.handleInt()
141

  
142
    
143
if __name__ == '__main__':
144
    setLogLevel( 'info' )
145
    net = TreeNet( depth=2, fanout=2 )
146
    net.start()
147
    app = Consoles( net.hosts, width=2 )
148
    app.mainloop()
149
    net.stop()

Also available in: Unified diff