X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=python%2Fvserver.py;h=64cc6812c5454932d4121dd517d5fc85fbda48c9;hb=5042d11bf25cac8a08cfffe760ff0f9fbb2cabd7;hp=282de703863c8220fdacc67953ef6e6c4572c93a;hpb=3d230d41bd4d53147a30d227ad31d9da49738b8b;p=util-vserver.git diff --git a/python/vserver.py b/python/vserver.py index 282de70..64cc681 100644 --- a/python/vserver.py +++ b/python/vserver.py @@ -4,9 +4,14 @@ import errno import fcntl import os import re +import sys +import time +import traceback +import mountimpl import linuxcaps import passfdimpl +import utmp import vserverimpl from util_vserver_vars import * @@ -41,6 +46,9 @@ FLAGS_NAMESPACE = 128 class VServer: + INITSCRIPTS = [('/etc/rc.vinit', 'start'), + ('/etc/rc.d/rc', '%(runlevel)d')] + def __init__(self, name): self.name = name @@ -73,7 +81,7 @@ class VServer: return os.chroot("%s/%s" % (VROOTDIR, self.name)) - def open(self, filename, mode = "r"): + def open(self, filename, mode = "r", bufsize = -1): (sendsock, recvsock) = passfdimpl.socketpair() child_pid = os.fork() @@ -128,13 +136,128 @@ class VServer: if not fd: throw() - return os.fdopen(fd) + return os.fdopen(fd, mode, bufsize) - def enter(self): + def __do_chcontext(self, state_file = None): - state_file = open("/var/run/vservers/%s.ctx" % self.name, "w") - self.__do_chroot() vserverimpl.chcontext(self.ctx, self.remove_caps) + if not state_file: + return print >>state_file, "S_CONTEXT=%d" % self.ctx print >>state_file, "S_PROFILE=%s" % self.config.get("S_PROFILE", "") state_file.close() + + def __prep(self, runlevel, log): + + """ Perform all the crap that the vserver script does before + actually executing the startup scripts. """ + + # remove /var/run and /var/lock/subsys files + # but don't remove utmp from the top-level /var/run + RUNDIR = "/var/run" + LOCKDIR = "/var/lock/subsys" + filter_fn = lambda fs: filter(lambda f: f != 'utmp', fs) + garbage = reduce((lambda (out, ff), (dir, subdirs, files): + (out + map((dir + "/").__add__, ff(files)), + lambda fs: fs)), + list(os.walk(RUNDIR)), + ([], filter_fn))[0] + garbage += filter(os.path.isfile, map((LOCKDIR + "/").__add__, + os.listdir(LOCKDIR))) + for f in garbage: + os.unlink(f) + + # set the initial runlevel + f = open(RUNDIR + "/utmp", "w") + utmp.set_runlevel(f, runlevel) + f.close() + + # mount /proc and /dev/pts + self.__do_mount("none", "/proc", "proc") + # XXX - magic mount options + self.__do_mount("none", "/dev/pts", "devpts", 0, "gid=5,mode=0620") + + def __do_mount(self, *mount_args): + + try: + mountimpl.mount(*mount_args) + except OSError, ex: + if ex.errno == errno.EBUSY: + # assume already mounted + return + raise ex + + def enter(self): + + state_file = open("/var/run/vservers/%s.ctx" % self.name, "w") + self.__do_chroot() + self.__do_chcontext(state_file) + + def start(self, wait, runlevel = 3): + + child_pid = os.fork() + if child_pid == 0: + # child process + try: + # get a new session + os.setsid() + + # open state file to record vserver info + state_file = open("/var/run/vservers/%s.ctx" % self.name, "w") + + # use /dev/null for stdin, /var/log/boot.log for stdout/err + os.close(0) + os.close(1) + os.open("/dev/null", os.O_RDONLY) + self.__do_chroot() + log = open("/var/log/boot.log", "w", 0) + os.dup2(1, 2) + + print >>log, ("%s: starting the virtual server %s" % + (time.asctime(time.gmtime()), self.name)) + + # perform pre-init cleanup + self.__prep(runlevel, log) + + # execute each init script in turn + # XXX - we don't support all scripts that vserver script does + cmd_pid = 0 + for cmd in self.INITSCRIPTS + [None]: + # wait for previous command to terminate, unless it + # is the last one and the caller has specified to wait + if cmd_pid and (cmd != None or wait): + try: + os.waitpid(cmd_pid, 0) + except: + print >>log, "error waiting for %s:" % cmd_pid + traceback.print_exc() + + # end of list + if cmd == None: + os._exit(0) + + # fork and exec next command + cmd_pid = os.fork() + if cmd_pid == 0: + try: + # enter vserver context + self.__do_chcontext(state_file) + arg_subst = { 'runlevel': runlevel } + cmd_args = [cmd[0]] + map(lambda x: x % arg_subst, + cmd[1:]) + print >>log, "executing '%s'" % " ".join(cmd_args) + os.execl(cmd[0], *cmd_args) + except: + traceback.print_exc() + os._exit(1) + else: + # don't want to write state_file multiple times + state_file = None + + # we get here due to an exception in the top-level child process + except Exception, ex: + traceback.print_exc() + os._exit(0) + + # parent process + return child_pid