diff --git a/examples/bind.py b/examples/bind.py index 2c317cf19543e8a151325762aca0e2e061f16995..af02254a1909aa83506ec32bc20dc8d59288b88a 100755 --- a/examples/bind.py +++ b/examples/bind.py @@ -7,191 +7,33 @@ """ from mininet.net import Mininet -from mininet.node import Host +from mininet.node import Host, HostWithPrivateDirs from mininet.cli import CLI -from mininet.util import errFail, quietRun, errRun from mininet.topo import SingleSwitchTopo from mininet.log import setLogLevel, info, debug -from os.path import realpath from functools import partial -# Utility functions for unmounting a tree - -MNRUNDIR = realpath( '/var/run/mn' ) - -def mountPoints(): - "Return list of mounted file systems" - mtab, _err, _ret = errFail( 'cat /proc/mounts' ) - lines = mtab.split( '\n' ) - mounts = [] - for line in lines: - if not line: - continue - fields = line.split( ' ') - mount = fields[ 1 ] - mounts.append( mount ) - return mounts - -def unmountAll( rootdir=MNRUNDIR ): - "Unmount all mounts under a directory tree" - rootdir = realpath( rootdir ) - # Find all mounts below rootdir - # This is subtle because /foo is not - # a parent of /foot - dirslash = rootdir + '/' - mounts = [ m for m in mountPoints() - if m == dir or m.find( dirslash ) == 0 ] - # Unmount them from bottom to top - mounts.sort( reverse=True ) - for mount in mounts: - debug( 'Unmounting', mount, '\n' ) - _out, err, code = errRun( 'umount', mount ) - if code != 0: - info( '*** Warning: failed to umount', mount, '\n' ) - info( err ) - - -class HostWithPrivateDirs( Host ): - "Host with private directories" - - mnRunDir = MNRUNDIR - - def __init__(self, name, *args, **kwargs ): - """privateDirs: list of private directories - remounts: dirs to remount - unmount: unmount dirs in cleanup? (True) - Note: if unmount is False, you must call unmountAll() - manually.""" - self.privateDirs = kwargs.pop( 'privateDirs', [] ) - self.remounts = kwargs.pop( 'remounts', [] ) - self.unmount = kwargs.pop( 'unmount', True ) - Host.__init__( self, name, *args, **kwargs ) - self.rundir = '%s/%s' % ( self.mnRunDir, name ) - self.root, self.private = None, None # set in createBindMounts - if self.privateDirs: - self.privateDirs = [ realpath( d ) for d in self.privateDirs ] - self.createBindMounts() - # These should run in the namespace before we chroot, - # in order to put the right entries in /etc/mtab - # Eventually this will allow a local pid space - # Now we chroot and cd to wherever we were before. - pwd = self.cmd( 'pwd' ).strip() - self.sendCmd( 'exec chroot', self.root, 'bash -ms mininet:' - + self.name ) - self.waiting = False - self.cmd( 'cd', pwd ) - # In order for many utilities to work, - # we need to remount /proc and /sys - self.cmd( 'mount /proc' ) - self.cmd( 'mount /sys' ) - - def mountPrivateDirs( self ): - "Create and bind mount private dirs" - for dir_ in self.privateDirs: - privateDir = self.private + dir_ - errFail( 'mkdir -p ' + privateDir ) - mountPoint = self.root + dir_ - errFail( 'mount -B %s %s' % - ( privateDir, mountPoint) ) - - def mountDirs( self, dirs ): - "Mount a list of directories" - for dir_ in dirs: - mountpoint = self.root + dir_ - errFail( 'mount -B %s %s' % - ( dir_, mountpoint ) ) - - @classmethod - def findRemounts( cls, fstypes=None ): - """Identify mount points in /proc/mounts to remount - fstypes: file system types to match""" - if fstypes is None: - fstypes = [ 'nfs' ] - dirs = quietRun( 'cat /proc/mounts' ).strip().split( '\n' ) - remounts = [] - for dir_ in dirs: - line = dir_.split() - mountpoint, fstype = line[ 1 ], line[ 2 ] - # Don't re-remount directories!!! - if mountpoint.find( cls.mnRunDir ) == 0: - continue - if fstype in fstypes: - remounts.append( mountpoint ) - return remounts - - def createBindMounts( self ): - """Create a chroot directory structure, - with self.privateDirs as private dirs""" - errFail( 'mkdir -p '+ self.rundir ) - unmountAll( self.rundir ) - # Create /root and /private directories - self.root = self.rundir + '/root' - self.private = self.rundir + '/private' - errFail( 'mkdir -p ' + self.root ) - errFail( 'mkdir -p ' + self.private ) - # Recursively mount / in private doort - # note we'll remount /sys and /proc later - errFail( 'mount -B / ' + self.root ) - self.mountDirs( self.remounts ) - self.mountPrivateDirs() - - def unmountBindMounts( self ): - "Unmount all of our bind mounts" - unmountAll( self.rundir ) - - def popen( self, *args, **kwargs ): - "Popen with chroot support" - chroot = kwargs.pop( 'chroot', True ) - mncmd = kwargs.get( 'mncmd', - [ 'mnexec', '-a', str( self.pid ) ] ) - if chroot: - mncmd = [ 'chroot', self.root ] + mncmd - kwargs[ 'mncmd' ] = mncmd - return Host.popen( self, *args, **kwargs ) - - def cleanup( self ): - """Clean up, then unmount bind mounts - unmount: actually unmount bind mounts?""" - # Wait for process to actually terminate - self.shell.wait() - Host.cleanup( self ) - if self.unmount: - self.unmountBindMounts() - errFail( 'rmdir ' + self.root ) - - -# Convenience aliases - -findRemounts = HostWithPrivateDirs.findRemounts - - # Sample usage def testHostWithPrivateDirs(): "Test bind mounts" topo = SingleSwitchTopo( 10 ) - remounts = findRemounts( fstypes=[ 'nfs' ] ) privateDirs = [ '/var/log', '/var/run' ] - host = partial( HostWithPrivateDirs, remounts=remounts, - privateDirs=privateDirs, unmount=False ) + host = partial( HostWithPrivateDirs, + privateDirs=privateDirs ) net = Mininet( topo=topo, host=host ) net.start() info( 'Private Directories:', privateDirs, '\n' ) CLI( net ) net.stop() - # We do this all at once to save a bit of time - info( 'Unmounting host bind mounts...\n' ) - unmountAll() if __name__ == '__main__': - unmountAll() setLogLevel( 'info' ) testHostWithPrivateDirs() info( 'Done.\n') - diff --git a/mininet/node.py b/mininet/node.py index e5e8cb13be4ed8dd9006ca95bc6fdb5b4e9b88b0..a9852b29fb94571cc0c82be7c1243698081eff6e 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -725,6 +725,23 @@ def init( cls ): mountCgroups() cls.inited = True +class HostWithPrivateDirs( Host ): + "Host with private directories" + + def __init__(self, *args, **kwargs ): + """privateDirs: list of private directories""" + + self.privateDirs = kwargs.pop( 'privateDirs', [] ) + Host.__init__( self, *args, **kwargs ) + self.mountPrivateDirs() + + def mountPrivateDirs( self ): + "Mount tmpfs for each private directory" + for dir_ in self.privateDirs: + self.cmd( 'mkdir -p ' + dir_ ) + self.cmd( 'mount -n -t tmpfs tmpfs %s' % dir_ ) + + # Some important things to note: #