X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=python%2Fvserver.py;h=b621e4c6602eaf7bac11a0c98f5cda5292059e55;hb=da4283f4995283be5020e58eaf7fb02d014a07da;hp=16ce4d009684d2bdd3a3918be63f285afd839406;hpb=d920f1a8a39dc2bd398bd2a6a305778fa1b47fcb;p=util-vserver.git diff --git a/python/vserver.py b/python/vserver.py index 16ce4d0..b621e4c 100644 --- a/python/vserver.py +++ b/python/vserver.py @@ -1,6 +1,6 @@ # Copyright 2005 Princeton University -#$Id: vserver.py,v 1.58 2007/07/17 17:51:27 faiyaza Exp $ +#$Id: vserver.py,v 1.71 2007/08/02 15:26:42 dhozac Exp $ import errno import fcntl @@ -11,6 +11,8 @@ import signal import sys import time import traceback +import subprocess +import resource import mountimpl import runcmd @@ -21,16 +23,6 @@ import cpulimit, bwlimit from vserverimpl import VS_SCHED_CPU_GUARANTEED as SCHED_CPU_GUARANTEED from vserverimpl import DLIMIT_INF from vserverimpl import VC_LIM_KEEP - -from vserverimpl import RLIMIT_CPU -from vserverimpl import RLIMIT_RSS -from vserverimpl import RLIMIT_NPROC -from vserverimpl import RLIMIT_NOFILE -from vserverimpl import RLIMIT_MEMLOCK -from vserverimpl import RLIMIT_AS -from vserverimpl import RLIMIT_LOCKS -from vserverimpl import RLIMIT_SIGPENDING -from vserverimpl import RLIMIT_MSGQUEUE from vserverimpl import VLIMIT_NSOCK from vserverimpl import VLIMIT_OPENFD from vserverimpl import VLIMIT_ANON @@ -48,19 +40,19 @@ FLAGS_HIDEINFO = 32 FLAGS_ULIMIT = 64 FLAGS_NAMESPACE = 128 -RLIMITS = {"CPU": RLIMIT_CPU, - "RSS": RLIMIT_RSS, - "NPROC": RLIMIT_NPROC, - "NOFILE": RLIMIT_NOFILE, - "MEMLOCK": RLIMIT_MEMLOCK, - "AS": RLIMIT_AS, - "LOCKS": RLIMIT_LOCKS, - "SIGPENDING": RLIMIT_SIGPENDING, - "MSGQUEUE": RLIMIT_MSGQUEUE, - "NSOCK": VLIMIT_NSOCK, - "OPENFD": VLIMIT_OPENFD, - "ANON": VLIMIT_ANON, - "SHMEM": VLIMIT_SHMEM} +RLIMITS = { "NSOCK": VLIMIT_NSOCK, + "OPENFD": VLIMIT_OPENFD, + "ANON": VLIMIT_ANON, + "SHMEM": VLIMIT_SHMEM} + +# add in the platform supported rlimits +for entry in resource.__dict__.keys(): + if entry.find("RLIMIT_")==0: + k = entry[len("RLIMIT_"):] + if not RLIMITS.has_key(k): + RLIMITS[k]=resource.__dict__[entry] + else: + print "WARNING: duplicate RLIMITS key %s" % k class NoSuchVServer(Exception): pass @@ -69,23 +61,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 KeyError, e: - # No mapping exists for this option - raise e - 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) @@ -100,8 +99,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: @@ -184,16 +213,45 @@ class VServer: def set_capabilities_config(self, capabilities): self.config.update('bcapabilities', capabilities) - self.set_capabilities(capabilities) + self.set_capabilities(capabilities) def get_capabilities(self): return vserverimpl.bcaps2text(vserverimpl.getbcaps(self.ctx)) def get_capabilities_config(self): - return self.config.get('bcapabilities') + return self.config.get('bcapabilities', '') + + 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("/") @@ -335,8 +393,9 @@ class VServer: ([], filter_fn))[0] garbage += filter(os.path.isfile, map((LOCKDIR + "/").__add__, os.listdir(LOCKDIR))) - for f in garbage: - os.unlink(f) + if False: + for f in garbage: + os.unlink(f) # set the initial runlevel f = open(RUNDIR + "/utmp", "w") @@ -377,11 +436,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" % @@ -393,17 +455,17 @@ 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]: - 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) - except: - traceback.print_exc() - os._exit(1) + 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) + except: + traceback.print_exc() + os._exit(1) # we get here due to an exception in the top-level child process except Exception, ex: @@ -422,11 +484,17 @@ class VServer: def init_disk_info(self): cmd = "/usr/sbin/vdu --script --space --inodes --blocksize 1024 --xid %d %s" % (self.ctx, self.dir) - (child_stdin, child_stdout, child_stderr) = os.popen3(cmd) - child_stdin.close() - line = child_stdout.readline() + p = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, + close_fds=True) + p.stdin.close() + line = p.stdout.readline() if not line: - sys.stderr.write(child_stderr.readline()) + sys.stderr.write(p.stderr.read()) + p.stdout.close() + p.stderr.close() + ret = p.wait() + (space, inodes) = line.split() self.disk_inodes = int(inodes) self.disk_blocks = int(space)