Logo Search packages:      
Sourcecode: umlrun version File versions  Download package

umlrun.py

import sys
import exceptions
import time
import os
import signal
import termios
import getopt
import ConfigParser
import pwd

00011 class UML:
    def __init__(self):
        self.umid = 'umlrun-%d' % os.getpid()
        self.verbose = False
        self.umlpid = None

    def __del__(self):
        if self.is_running():
            self.halt()

    def start(self, umlargs, verbose=None, timeout=60, interactive='auto'):
        uml = ['linux',
               'umid=' + self.umid]
        if verbose is not None:
            self.verbose = verbose
        self.saved_ttyattr = None
        if sys.stdout.isatty():
            self.saved_ttyattr = termios.tcgetattr(sys.stdout.fileno())
            
        if not self.verbose:
            uml.append('quiet')

        uml.extend(umlargs)

        self.umlpid = os.fork()
        if self.umlpid == 0:
            os.execvp(uml[0], uml)
            sys.exit(1)

        self.log("Waiting for UML to start up...")
        timeleft = timeout
        while timeleft > 0:
            if self.wait(nohang=True) is not None:
                raise Error('UML exited unexpectedly')

            try:
                self.mconsole('version')
                break
            except MConsoleConnectionFailed:
                pass
            time.sleep(1)
            timeleft -= 1
        if timeleft <= 0:
            raise TimeoutError('UML did not start up within %d seconds' % timeout)

        self.log("UML startup OK (pid %s)" % self.umlpid)

    def is_running(self):
        return hasattr(self, 'umlpid') and self.umlpid != None

    def wait(self, nohang=False):
        if not self.is_running():
            return None

        if nohang:
            flags = os.WNOHANG
        else:
            flags = 0
        pid, status = os.waitpid(self.umlpid, flags)
        if pid == self.umlpid:
            self.umlpid = None
            self.restoretty()
            return status
        return None
        
    def run(self):
        self.start()
        self.wait()

    def mconsole(self, command):
        fd = os.popen('uml_mconsole %s %s 2>/dev/null' % (self.umid, command))
        output = fd.read().rstrip()
        status = fd.close()
        if status != None or len(output) == 0:
            raise MConsoleConnectionFailed()

        if ' ' in output:
            status, rest = output.split(' ', 1)
        else:
            status, rest = output, None

        if status != 'OK':
            raise MConsoleError(status, rest)

        if rest:
            return rest
        return True

    def halt(self, timeout=60):
        if not self.is_running():
            return

        self.log("Halting UML via mconsole")
        try:
            self.mconsole('halt')
        except:
            self.kill()

        return self.wait()

    def kill(self, timeout=2):
        self.log("Killing UML with SIGTERM")
        os.kill(self.umlpid, signal.SIGTERM)
        timeleft = timeout
        while timeleft > 0:
            if self.wait(nohang=True) is not None:
                return
            timeleft -= 1

        if timeleft <= 0:
            self.log("Killing UML with SIGKILL")
            os.kill(self.umlpid, signal.SIGKILL)

        return self.wait()

    def restoretty(self):
        if self.saved_ttyattr:
            termios.tcsetattr(sys.stdout.fileno(), termios.TCSANOW, self.saved_ttyattr)

    def log(self, msg):
        if self.verbose:
            sys.stderr.write(msg + '\r\n')

00134 class UMLRun(UML):
    def __init__(self):
        UML.__init__(self)
        self.control = None
        self.interactive = None
        self.version = None

    def start(self, umlargs, verbose=0, timeout=60, interactive='auto'):
        if interactive == 'auto':
            if sys.stdin.isatty() and sys.stdout.isatty():
                self.interactive = 1
            else:
                self.interactive = 0
        else:
            self.interactive = interactive

        if self.interactive:
            ssl1 = 'ssl1=tty:/dev/tty'
        else:
            ssl1 = 'ssl1=fd:0,fd:1'

        UML.start(self, umlargs + ['con=pts', 'umlrun=ssl0,ssl1', 'ssl0=pts', ssl1],
                  verbose, timeout)

        control_pts = None
        timeleft = timeout
        self.log("Waiting for umlrun-server to start up...")
        while timeleft > 0:
            control_pts = self._ptspath('ssl0')
            if control_pts:
                break

            time.sleep(1)
            timeleft -= 1
        if timeleft <= 0:
            raise TimeoutError('umlrun-server did not start up within %d seconds' % timeout)

        self.log("umlrun-server startup OK")

        self.control = open(control_pts, 'r+')

        self.version = self.control.readline().rstrip()
        self.log('umlrun-server version is ' + self.version)

    def shellcommand(self, args):
        if self.interactive:
            self._command('exec_interactive', args)
        else:
            self._command('exec', args)

    def setenv(self, name, value=None):
        if value == None:
            value = os.getenv(name)
            if value == None:
                return
        self._command('setenv', name, value)

    def mounthost(self):
        if self.version < 2:
            raise InterfaceUnsupported('mounthost')

        self._command('mount_host', os.getcwd())

    def shutdown(self, timeout=60):
        killed = 0
        
        if self.control:
            self.log("Waiting for UML to shut down...")
            self._command('shutdown')
            self.control.close()
            self.wait()
        else:
            UML.halt(self, timeout)

    def fast_shutdown(self):
        if self.version < 3:
            raise InterfaceUnsupported('fast_shutdown')
        self._command('FASTSHUTDOWN')

    def adduser(self, username, uid):
        if self.version < 3:
            raise InterfaceUnsupported('adduser')
        self._command('adduser', username, uid)

    def _command(self, cmd, *args):
        self.control.write('%s %s\n' % (cmd.upper(), ' '.join(args)))
        line = self.control.readline()[:-1]
        status, result = line.split(' ', 1)
        self.log('_command(%s, %s) -> %s %s' % (cmd, ', '.join(args), status, result))
        if int(status) != 200:
            raise CommandError(cmd, status, result)

    def _ptspath(self, dev):
        result = self.mconsole('config ' + dev)
        if result == 'pts':
            return None
        elif result[:4] == 'pts:':
            return result[4:]
        else:
            raise Error('Unexpected result from mconsole config query: ' + result)


00236 class UMLI(UML):
    def __init__(self, argv):
        UML.__init__(self)

        # Choose a default console mode based on the environment
        if os.getenv('STY'):
            self.consoleMode = 'screen'
        elif os.getenv('DISPLAY'):
            self.consoleMode = 'xterm'
        else:
            self.consoleMode = 'console1'

        self.root = None
        self.session = None
        self.modify = False

        self.config = ConfigParser.ConfigParser()
        self.config.read(('/etc/umli.conf',os.path.expanduser('~/.umli.conf')))

        opts, args = getopt.getopt(argv, 'c:r:xs:vm',
                                   ['console=',
                                    'root=',
                                    'session=',
                                    'verbose',
                                    'modify'])

        for opt, arg in opts:
            if opt == '-x':
                self.consoleMode = 'xterm'
            elif opt in ('-c', '--console'):
                self.consoleMode = arg
            elif opt in ('-r', '--root'):
                self.root = arg
            elif opt in ('-s', '--session'):
                self.session = arg
            elif opt in ('-v', '--verbose'):
                self.verbose = True
            elif opt in ('-m', '--modify'):
                self.modify = True

        if 'single' in args:
            self.consoleMode = 'console0'


        self.cmdline = self.consoleModeArgs() + self.rootArgs() + self.globalArgs() + args

    def __del__(self):
        if hasattr(self, 'cow') and hasattr(self, 'removeCow') and self.removeCow:
            try:
                os.unlink(self.cow)
            except:
                pass
        UML.__del__(self)

    def start(self):
        UML.start(self, self.cmdline)

        if self.consoleMode == 'screen':
            activateConsoles = ['con%d' % x for x in range(1,7)]
            while self.is_running() and len(activateConsoles) > 0:
                time.sleep(1)

                for con in activateConsoles:
                    channel = self.mconsole('config %s' % con)
                    if channel and channel.startswith('pts:'):
                        device = channel.split(':', 1)[1]
                        if os.spawnlp(os.P_WAIT, 'screen', 'screen', device) == 0:
                            activateConsoles.remove(con)

    def consoleModeArgs(self):
        if self.consoleMode == 'console1':
            # Default mode of operation:
            # get output from console 0 (initial console), no input
            # I/O from/to user on console 1 (VC #1)
            return ['con0=null,fd:1', 'con1=tty:/dev/tty', 'con=none']
        if self.consoleMode == 'console0':
            # Only console 0, for single-user
            return ['con0=tty:/dev/tty','con=none']
        if self.consoleMode == 'xterm':
            # Each console in its own xterm
            return ['con=xterm']
        if self.consoleMode == 'screen':
            # Initial console on tty, other consoles each on their own screen
            return ['con0=tty:/dev/tty','con=pts']
        raise RuntimeError('Unrecognized console mode: %s' % self.consoleMode)

    def rootArgs(self):
        root = self.root
        if root is not None:
            # Search path for root fs
            if self.config.has_option('umli', 'rootpath'):
                for rootdir in self.config.get('umli', 'rootpath').split(os.pathsep):
                    testroot = os.path.join(rootdir, self.root)
                    if os.path.exists(testroot):
                        root = testroot
                        break

            while os.path.isdir(root):
                root = os.path.join(root, 'default')

            # Collapse symlinks
            root = os.path.realpath(root)

        if self.modify:
            self.cow = None
        else:
            sessionDir = self.userSessionDir()

            if self.session is None:
                self.cow = os.path.join(sessionDir, 'umli-%s.cow' % os.getpid())
                self.removeCow = True
            else:
                self.cow = os.path.join(sessionDir,'%s.cow' % self.session)
                self.removeCow = False

        ret = []
        if self.cow:
            ret.append('root=/dev/ubd0')
            if os.path.exists(self.cow):
                ret.append('ubd0=%s' % self.cow)
            elif root is not None:
                ret.append('ubd0=%s,%s' % (self.cow, root))
            else:
                raise Error('Session "%s" not found' % self.session)
        elif root is not None:
            ret.append('root=/dev/ubd0')
            ret.append('ubd0=%s' % root)

        return ret

    def globalArgs(self):
        if self.config.has_option('umli', 'args'):
            return self.config.get('umli', 'args').split()
        return []

    def userSessionDir(self):
        sessionDir = '' # cwd
        if self.config.has_option('umli', 'sessiondir'):
            sessionDir = self.config.get('umli', 'sessiondir')
        user = pwd.getpwuid(os.getuid())[0]
        userSessionDir = os.path.join(sessionDir, user)
        if os.path.isdir(userSessionDir):
            stat = os.stat(userSessionDir)
            if stat.st_uid != os.getuid() or stat.st_mode & 002:
                raise RuntimeError('Suspicious ownership or permissions on directory %s' % userSessionDir)
            return userSessionDir
        os.mkdir(userSessionDir, 0770)
        return userSessionDir
        
00385 class Error(exceptions.RuntimeError):
    pass


00389 class CommandError(Error):
    def __init__(self, command, status, result):
        self.command = command
        self.status = status
        self.result = result
        Error.__init__(self, command + ': ' + status + ' ' + result)

00396 class InterfaceUnsupported(Error):
    def __init__(self, command):
        self.command = command
        Error.__init__(self, 'Interface not supported by umlrun-server')

00401 class TimeoutError(Error):
    def __init__(self, text):
        Error.__init__(self, text)

00405 class MConsoleConnectionFailed(Error):
    pass

00408 class MConsoleError(Error):
    def __init__(self, status, result):
        Error.__init__(self, 'mconsole: ' + status + ' ' + result)

# if __name__ == '__main__':
#     # simple self-test
#     uml = UMLRun()
#     try:
#         uml.start(umlargs=['eth0=tuntap,,,192.168.10.1',
#                            'ubd0=/tmp/cow,/home/mdz/.umldeb/images/unstable/image',
#                            'con=xterm'],
#                   verbose=0,interactive=0)
#         uml.setenv('FOO', 'bar')
#         #print "Executing a shell command:"
#         uml.shellcommand('echo "Hello, world! (FOO=$FOO)"')
#         uml.shellcommand('/bin/bash -i')
#     finally:
#         uml.halt()
#         os.remove('/tmp/cow')

Generated by  Doxygen 1.6.0   Back to index