Statistics
| Branch: | Tag: | Revision:

mininet / examples / bind.py @ 9bfc7c77

History | View | Annotate | Download (6.28 KB)

1 5ae8c936 Bob Lantz
#!/usr/bin/python
2
3
"""
4
bind.py: Bind mount prototype
5

6
This creates hosts with private directories as desired.
7
"""
8
9
from mininet.net import Mininet
10 f3442903 Bob Lantz
from mininet.node import Host
11 5ae8c936 Bob Lantz
from mininet.cli import CLI
12
from mininet.util import errFail, quietRun, errRun
13
from mininet.topo import SingleSwitchTopo
14
from mininet.log import setLogLevel, info, debug
15
16 f3442903 Bob Lantz
from os.path import realpath
17 5ae8c936 Bob Lantz
from functools import partial
18
19 f3442903 Bob Lantz
20 5ae8c936 Bob Lantz
# Utility functions for unmounting a tree
21
22 f3442903 Bob Lantz
MNRUNDIR = realpath( '/var/run/mn' )
23
24 5ae8c936 Bob Lantz
def mountPoints():
25
    "Return list of mounted file systems"
26
    mtab, _err, _ret = errFail( 'cat /proc/mounts' )
27
    lines = mtab.split( '\n' )
28
    mounts = []
29
    for line in lines:
30
        if not line:
31
            continue
32
        fields = line.split( ' ')
33
        mount = fields[ 1 ]
34
        mounts.append( mount )
35
    return mounts
36
37 445c0959 Bob Lantz
def unmountAll( rootdir=MNRUNDIR ):
38 5ae8c936 Bob Lantz
    "Unmount all mounts under a directory tree"
39 445c0959 Bob Lantz
    rootdir = realpath( rootdir )
40
    # Find all mounts below rootdir
41 5ae8c936 Bob Lantz
    # This is subtle because /foo is not
42
    # a parent of /foot
43 445c0959 Bob Lantz
    dirslash = rootdir + '/'
44 5ae8c936 Bob Lantz
    mounts = [ m for m in mountPoints()
45
              if m == dir or m.find( dirslash ) == 0 ]
46
    # Unmount them from bottom to top
47
    mounts.sort( reverse=True )
48
    for mount in mounts:
49
        debug( 'Unmounting', mount, '\n' )
50 445c0959 Bob Lantz
        _out, err, code = errRun( 'umount', mount )
51 5ae8c936 Bob Lantz
        if code != 0:
52
            info( '*** Warning: failed to umount', mount, '\n' )
53
            info( err )
54
55
56
class HostWithPrivateDirs( Host ):
57
    "Host with private directories"
58
59 f3442903 Bob Lantz
    mnRunDir = MNRUNDIR
60 5ae8c936 Bob Lantz
61
    def __init__(self, name, *args, **kwargs ):
62 f3442903 Bob Lantz
        """privateDirs: list of private directories
63
           remounts: dirs to remount
64
           unmount: unmount dirs in cleanup? (True)
65
           Note: if unmount is False, you must call unmountAll()
66
           manually."""
67 5ae8c936 Bob Lantz
        self.privateDirs = kwargs.pop( 'privateDirs', [] )
68 f3442903 Bob Lantz
        self.remounts = kwargs.pop( 'remounts', [] )
69
        self.unmount = kwargs.pop( 'unmount', True )
70 5ae8c936 Bob Lantz
        Host.__init__( self, name, *args, **kwargs )
71
        self.rundir = '%s/%s' % ( self.mnRunDir, name )
72 445c0959 Bob Lantz
        self.root, self.private = None, None  # set in createBindMounts
73 5ae8c936 Bob Lantz
        if self.privateDirs:
74
            self.privateDirs = [ realpath( d ) for d in self.privateDirs ]
75
            self.createBindMounts()
76
        # These should run in the namespace before we chroot,
77
        # in order to put the right entries in /etc/mtab
78
        # Eventually this will allow a local pid space
79
        # Now we chroot and cd to wherever we were before.
80
        pwd = self.cmd( 'pwd' ).strip()
81
        self.sendCmd( 'exec chroot', self.root, 'bash -ms mininet:'
82
                       + self.name )
83
        self.waiting = False
84
        self.cmd( 'cd', pwd )
85
        # In order for many utilities to work,
86
        # we need to remount /proc and /sys
87
        self.cmd( 'mount /proc' )
88
        self.cmd( 'mount /sys' )
89
90
    def mountPrivateDirs( self ):
91
        "Create and bind mount private dirs"
92 445c0959 Bob Lantz
        for dir_ in self.privateDirs:
93
            privateDir = self.private + dir_
94 5ae8c936 Bob Lantz
            errFail( 'mkdir -p ' + privateDir )
95 445c0959 Bob Lantz
            mountPoint = self.root + dir_
96 5ae8c936 Bob Lantz
            errFail( 'mount -B %s %s' %
97
                           ( privateDir, mountPoint) )
98
99 f3442903 Bob Lantz
    def mountDirs( self, dirs ):
100
        "Mount a list of directories"
101 445c0959 Bob Lantz
        for dir_ in dirs:
102
            mountpoint = self.root + dir_
103 f3442903 Bob Lantz
            errFail( 'mount -B %s %s' %
104 445c0959 Bob Lantz
                     ( dir_, mountpoint ) )
105 f3442903 Bob Lantz
106
    @classmethod
107 445c0959 Bob Lantz
    def findRemounts( cls, fstypes=None ):
108 f3442903 Bob Lantz
        """Identify mount points in /proc/mounts to remount
109
           fstypes: file system types to match"""
110 445c0959 Bob Lantz
        if fstypes is None:
111
            fstypes = [ 'nfs' ]
112 f3442903 Bob Lantz
        dirs = quietRun( 'cat /proc/mounts' ).strip().split( '\n' )
113
        remounts = []
114 445c0959 Bob Lantz
        for dir_ in dirs:
115
            line = dir_.split()
116 5ae8c936 Bob Lantz
            mountpoint, fstype = line[ 1 ], line[ 2 ]
117
            # Don't re-remount directories!!!
118 f3442903 Bob Lantz
            if mountpoint.find( cls.mnRunDir ) == 0:
119 5ae8c936 Bob Lantz
                continue
120
            if fstype in fstypes:
121 f3442903 Bob Lantz
                remounts.append( mountpoint )
122
        return remounts
123 5ae8c936 Bob Lantz
124
    def createBindMounts( self ):
125
        """Create a chroot directory structure,
126
           with self.privateDirs as private dirs"""
127
        errFail( 'mkdir -p '+ self.rundir )
128
        unmountAll( self.rundir )
129
        # Create /root and /private directories
130
        self.root = self.rundir + '/root'
131
        self.private = self.rundir + '/private'
132
        errFail( 'mkdir -p ' + self.root )
133
        errFail( 'mkdir -p ' + self.private )
134
        # Recursively mount / in private doort
135
        # note we'll remount /sys and /proc later
136
        errFail( 'mount -B / ' + self.root )
137 f3442903 Bob Lantz
        self.mountDirs( self.remounts )
138 5ae8c936 Bob Lantz
        self.mountPrivateDirs()
139
140
    def unmountBindMounts( self ):
141
        "Unmount all of our bind mounts"
142
        unmountAll( self.rundir )
143
144
    def popen( self, *args, **kwargs ):
145
        "Popen with chroot support"
146
        chroot = kwargs.pop( 'chroot', True )
147
        mncmd = kwargs.get( 'mncmd',
148
                           [ 'mnexec', '-a', str( self.pid ) ] )
149
        if chroot:
150
            mncmd = [ 'chroot', self.root ] + mncmd
151
            kwargs[ 'mncmd' ] = mncmd
152
        return Host.popen( self, *args, **kwargs )
153
154
    def cleanup( self ):
155 f3442903 Bob Lantz
        """Clean up, then unmount bind mounts
156
           unmount: actually unmount bind mounts?"""
157 5ae8c936 Bob Lantz
        # Wait for process to actually terminate
158
        self.shell.wait()
159
        Host.cleanup( self )
160 f3442903 Bob Lantz
        if self.unmount:
161
            self.unmountBindMounts()
162
            errFail( 'rmdir ' + self.root )
163
164
165
# Convenience aliases
166
167
findRemounts = HostWithPrivateDirs.findRemounts
168
169 5ae8c936 Bob Lantz
170
# Sample usage
171
172
def testHostWithPrivateDirs():
173
    "Test bind mounts"
174 f3442903 Bob Lantz
    topo = SingleSwitchTopo( 10 )
175
    remounts = findRemounts( fstypes=[ 'nfs' ] )
176 5ae8c936 Bob Lantz
    privateDirs = [ '/var/log', '/var/run' ]
177 f3442903 Bob Lantz
    host = partial( HostWithPrivateDirs, remounts=remounts,
178
                    privateDirs=privateDirs, unmount=False )
179 5ae8c936 Bob Lantz
    net = Mininet( topo=topo, host=host )
180
    net.start()
181 f3442903 Bob Lantz
    info( 'Private Directories:', privateDirs, '\n' )
182 5ae8c936 Bob Lantz
    CLI( net )
183
    net.stop()
184 f3442903 Bob Lantz
    # We do this all at once to save a bit of time
185
    info( 'Unmounting host bind mounts...\n' )
186
    unmountAll()
187 5ae8c936 Bob Lantz
188
189
if __name__ == '__main__':
190
    unmountAll()
191
    setLogLevel( 'info' )
192
    testHostWithPrivateDirs()
193 f3442903 Bob Lantz
    info( 'Done.\n')
194 5ae8c936 Bob Lantz
195
196