X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=python%2Fvserver.py;h=de8c16460d5df66b28e998bd4300630c2a99042b;hb=9b74b47baed4fe49c1c08226ba56e59512c6f269;hp=e92330906bc7c4344e10a748c775129acfea2eee;hpb=5280366ac34df35ffc0bd4bc86ec2a5b22951e4b;p=util-vserver.git diff --git a/python/vserver.py b/python/vserver.py index e923309..de8c164 100644 --- a/python/vserver.py +++ b/python/vserver.py @@ -1,6 +1,6 @@ # Copyright 2005 Princeton University -#$Id: vserver.py,v 1.62 2007/07/20 19:45:35 dhozac Exp $ +#$Id: vserver.py,v 1.72 2007/08/02 16:01:59 dhozac Exp $ import errno import fcntl @@ -14,9 +14,6 @@ import traceback import subprocess import resource -import mountimpl -import runcmd -import utmp import vserverimpl import cpulimit, bwlimit @@ -61,20 +58,30 @@ class VServerConfig: def __init__(self, name, directory): self.name = name self.dir = directory + self.cache = None + if not (os.path.isdir(self.dir) and + os.access(self.dir, os.R_OK | os.W_OK | os.X_OK)): + raise NoSuchVServer, "%s does not exist" % self.dir def get(self, option, default = None): try: - f = open(os.path.join(self.dir, option), "r") - buf = f.readline().rstrip() - f.close() - return buf - except IOError, e: + if self.cache: + return self.cache[option] + else: + f = open(os.path.join(self.dir, option), "r") + buf = f.read().rstrip() + f.close() + return buf + except: if default is not None: return default else: raise KeyError, "Key %s is not set for %s" % (option, self.name) def update(self, option, value): + if self.cache: + return + try: old_umask = os.umask(0022) filename = os.path.join(self.dir, option) @@ -89,8 +96,38 @@ class VServerConfig: f.write("%s\n" % value) f.close() os.umask(old_umask) - except KeyError, e: - raise KeyError, "Don't know how to handle %s, sorry" % option + except: + raise + + def unset(self, option): + if self.cache: + return + + try: + filename = os.path.join(self.dir, option) + os.unlink(filename) + try: + os.removedirs(os.path.dirname(filename)) + except: + pass + return True + except: + return False + + def cache_it(self): + self.cache = {} + def add_to_cache(cache, dirname, fnames): + for file in fnames: + full_name = os.path.join(dirname, file) + if os.path.islink(full_name): + fnames.remove(file) + elif (os.path.isfile(full_name) and + os.access(full_name, os.R_OK)): + f = open(full_name, "r") + cache[full_name.replace(os.path.join(self.dir, ''), + '')] = f.read().rstrip() + f.close() + os.path.walk(self.dir, add_to_cache, self.cache) class VServer: @@ -165,9 +202,6 @@ class VServer: minimum = int(self.config.get("rlimits/%s.min"%type.lower(),VC_LIM_KEEP)) return (hard,soft,minimum) - def set_WHITELISTED_config(self,whitelisted): - self.config.update('whitelisted', whitelisted) - def set_capabilities(self, capabilities): return vserverimpl.setbcaps(self.ctx, vserverimpl.text2bcaps(capabilities)) @@ -181,8 +215,37 @@ class VServer: def get_capabilities_config(self): return self.config.get('bcapabilities', '') - def __do_chroot(self): + def set_ipaddresses(self, addresses): + vserverimpl.netremove(self.ctx, "all") + for a in addresses.split(","): + vserverimpl.netadd(self.ctx, a) + + def set_ipaddresses_config(self, addresses): + i = 0 + for a in addresses.split(","): + self.config.update("interfaces/%d/ip" % i, a) + i += 1 + while self.config.unset("interfaces/%d/ip" % i): + i += 1 + self.set_ipaddresses(addresses) + + def get_ipaddresses_config(self): + i = 0 + ret = [] + while True: + r = self.config.get("interfaces/%d/ip" % i, '') + if r == '': + break + ret += [r] + i += 1 + return ",".join(ret) + + def get_ipaddresses(self): + # No clean way to do this right now. + return None + def __do_chroot(self): + self.config.cache_it() os.chroot(self.dir) os.chdir("/") @@ -330,18 +393,18 @@ class VServer: # set the initial runlevel f = open(RUNDIR + "/utmp", "w") - utmp.set_runlevel(f, runlevel) + vserverimpl.setrunlevel(f, runlevel) f.close() # mount /proc and /dev/pts - self.__do_mount("none", "/proc", "proc") + self.__do_mount("none", self.dir, "/proc", "proc") # XXX - magic mount options - self.__do_mount("none", "/dev/pts", "devpts", 0, "gid=5,mode=0620") + self.__do_mount("none", self.dir, "/dev/pts", "devpts", 0, "gid=5,mode=0620") def __do_mount(self, *mount_args): try: - mountimpl.mount(*mount_args) + vserverimpl.mount(*mount_args) except OSError, ex: if ex.errno == errno.EBUSY: # assume already mounted @@ -367,11 +430,14 @@ class VServer: state_file = open("/var/run/vservers/%s" % 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) + fd = os.open("/dev/null", os.O_RDONLY) + if fd != 0: + os.dup2(fd, 0) + os.close(fd) self.__do_chroot() log = open("/var/log/boot.log", "w", 0) + if log.fileno() != 1: + os.dup2(log.fileno(), 1) os.dup2(1, 2) print >>log, ("%s: starting the virtual server %s" % @@ -383,14 +449,14 @@ class VServer: # execute each init script in turn # XXX - we don't support all scripts that vserver script does self.__do_chcontext(state_file) - for cmd in self.INITSCRIPTS + [None]: + for cmd in self.INITSCRIPTS: try: # enter vserver context arg_subst = { 'runlevel': runlevel } cmd_args = [cmd[0]] + map(lambda x: x % arg_subst, cmd[1:]) print >>log, "executing '%s'" % " ".join(cmd_args) - os.spawnvp(os.P_WAIT,cmd[0],*cmd_args) + os.spawnvp(os.P_NOWAIT,cmd[0],cmd_args) except: traceback.print_exc() os._exit(1) @@ -439,10 +505,17 @@ class VServer: def create(vm_name, static = False, ctor = VServer): - options = [] + options = ['vuseradd'] if static: options += ['--static'] - runcmd.run('vuseradd', options + [vm_name]) + ret = os.spawnvp(os.P_WAIT, 'vuseradd', options + [vm_name]) + if !os.WIFEXITED(ret) || os.WEXITSTATUS(ret) != 0: + out = "system command ('%s') " % options + if os.WIFEXITED(ret): + out += "failed, rc = %d" % os.WEXITSTATUS(ret) + else: + out += "killed by signal %d" % os.WTERMSIG(ret) + raise SystemError, out vm_id = pwd.getpwnam(vm_name)[2] return ctor(vm_name, vm_id)