From: Faiyaz Ahmed Date: Mon, 23 Jul 2007 17:12:08 +0000 (+0000) Subject: Backport to before-util-vserver-0_30_213-merge X-Git-Tag: planetlab-4_1-rc1~2 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=1538c01b5a57f73bea965d069ffff430ef32970e;p=util-vserver.git Backport to before-util-vserver-0_30_213-merge --- diff --git a/python/vserver.py b/python/vserver.py index e4c7bd2..6bddee1 100644 --- a/python/vserver.py +++ b/python/vserver.py @@ -1,7 +1,5 @@ # Copyright 2005 Princeton University -#$Id: vserver.py,v 1.59 2007/07/17 17:56:04 faiyaza Exp $ - import errno import fcntl import os @@ -11,26 +9,17 @@ import signal import sys import time import traceback +import resource import mountimpl import runcmd import utmp -import vserverimpl +import vserverimpl, vduimpl 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,82 +37,48 @@ 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 -class VServerConfig: - def __init__(self, name, directory): - self.name = name - self.dir = directory - - 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 default is not None: - return default - else: - raise KeyError, "Key %s is not set for %s" % (option, self.name) - - def update(self, option, value): - try: - old_umask = os.umask(0022) - filename = os.path.join(self.dir, option) - try: - os.makedirs(os.path.dirname(filename), 0755) - except: - pass - f = open(filename, 'w') - if isinstance(value, list): - f.write("%s\n" % "\n".join(value)) - else: - 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 - - class VServer: INITSCRIPTS = [('/etc/rc.vinit', 'start'), ('/etc/rc.d/rc', '%(runlevel)d')] - def __init__(self, name, vm_id = None, vm_running = None): + def __init__(self, name, vm_id = None, vm_running = False): self.name = name self.rlimits_changed = False + self.config_file = "/etc/vservers/%s.conf" % name self.dir = "%s/%s" % (vserverimpl.VSERVER_BASEDIR, name) if not (os.path.isdir(self.dir) and os.access(self.dir, os.R_OK | os.W_OK | os.X_OK)): raise NoSuchVServer, "no such vserver: " + name - self.config = VServerConfig(name, "/etc/vservers/%s" % name) + self.config = {} + for config_file in ["/etc/vservers.conf", self.config_file]: + try: + self.config.update(self.__read_config_file(config_file)) + except IOError, ex: + if ex.errno != errno.ENOENT: + raise self.remove_caps = ~vserverimpl.CAP_SAFE; if vm_id == None: - vm_id = int(self.config.get('context')) + vm_id = int(self.config['S_CONTEXT']) self.ctx = vm_id - if vm_running == None: - vm_running = self.is_running() self.vm_running = vm_running def have_limits_changed(self): @@ -150,12 +105,15 @@ class VServer: def set_rlimit_config(self,type,hard,soft,minimum): """Generic set resource limit function for vserver""" + resources = {} if hard <> VC_LIM_KEEP: - self.config.update('rlimits/%s.hard' % type.lower(), hard) + resources["VS_%s_HARD"%type] = hard if soft <> VC_LIM_KEEP: - self.config.update('rlimits/%s.soft' % type.lower(), soft) + resources["VS_%s_SOFT"%type] = soft if minimum <> VC_LIM_KEEP: - self.config.update('rlimits/%s.min' % type.lower(), minimum) + resources["VS_%s_MINIMUM"%type] = minimum + if len(resources)>0: + self.update_resources(resources) self.set_rlimit_limit(type,hard,soft,minimum) def get_rlimit_limit(self,type): @@ -171,26 +129,59 @@ class VServer: def get_rlimit_config(self,type): """Generic get resource configuration function for vserver""" - hard = int(self.config.get("rlimits/%s.hard"%type.lower(),VC_LIM_KEEP)) - soft = int(self.config.get("rlimits/%s.soft"%type.lower(),VC_LIM_KEEP)) - minimum = int(self.config.get("rlimits/%s.min"%type.lower(),VC_LIM_KEEP)) + hard = int(self.config.get("VS_%s_HARD"%type,VC_LIM_KEEP)) + soft = int(self.config.get("VS_%s_SOFT"%type,VC_LIM_KEEP)) + minimum = int(self.config.get("VS_%s_MINIMUM"%type,VC_LIM_KEEP)) return (hard,soft,minimum) def set_WHITELISTED_config(self,whitelisted): - self.config.update('whitelisted', whitelisted) + resources = {'VS_WHITELISTED': whitelisted} + self.update_resources(resources) - def set_capabilities(self, capabilities): - return vserverimpl.setbcaps(self.ctx, vserverimpl.text2bcaps(capabilities)) + config_var_re = re.compile(r"^ *([A-Z_]+)=(.*)\n?$", re.MULTILINE) - def set_capabilities_config(self, capabilities): - self.config.update('bcapabilities', capabilities) - self.set_capabilities(capabilities) + def __read_config_file(self, filename): - def get_capabilities(self): - return vserverimpl.bcaps2text(vserverimpl.getbcaps(self.ctx)) - - def get_capabilities_config(self): - return self.config.get('bcapabilities') + f = open(filename, "r") + data = f.read() + f.close() + config = {} + for m in self.config_var_re.finditer(data): + (key, val) = m.groups() + config[key] = val.strip('"') + return config + + def __update_config_file(self, filename, newvars): + + # read old file, apply changes + f = open(filename, "r") + data = f.read() + f.close() + todo = newvars.copy() + changed = False + offset = 0 + for m in self.config_var_re.finditer(data): + (key, val) = m.groups() + newval = todo.pop(key, None) + if newval != None: + data = data[:offset+m.start(2)] + str(newval) + data[offset+m.end(2):] + offset += len(str(newval)) - (m.end(2)-m.start(2)) + changed = True + for (newkey, newval) in todo.items(): + data += "%s=%s\n" % (newkey, newval) + changed = True + + if not changed: + return + + # write new file + newfile = filename + ".new" + f = open(newfile, "w") + f.write(data) + f.close() + + # replace old file with new + os.rename(newfile, filename) def __do_chroot(self): @@ -244,7 +235,8 @@ class VServer: print "Unexpected error with setdlimit for context %d" % self.ctx - self.config.update('dlimits/0/space_total', block_limit) + resources = {'VS_DISK_MAX': block_limit} + self.update_resources(resources) def is_running(self): return vserverimpl.isrunning(self.ctx) @@ -268,13 +260,11 @@ class VServer: configuration file. This method does not modify the kernel CPU scheduling parameters for this context. """ - if sched_flags & SCHED_CPU_GUARANTEED: - cpu_guaranteed = cpu_share - else: - cpu_guaranteed = 0 - self.config.update('sched/fill-rate2', cpu_share) - self.config.update('sched/fill-rate', cpu_guaranteed) - + if cpu_share == int(self.config.get("CPULIMIT", -1)): + return + cpu_guaranteed = sched_flags & SCHED_CPU_GUARANTEED + cpu_config = { "CPULIMIT": cpu_share, "CPUGUARANTEED": cpu_guaranteed } + self.update_resources(cpu_config) if self.vm_running: self.set_sched(cpu_share, sched_flags) @@ -311,10 +301,11 @@ class VServer: def __do_chcontext(self, state_file): if state_file: - print >>state_file, "%u" % self.ctx + print >>state_file, "S_CONTEXT=%u" % self.ctx + print >>state_file, "S_PROFILE=" state_file.close() - if vserverimpl.chcontext(self.ctx, vserverimpl.text2bcaps(self.get_capabilities_config())): + if vserverimpl.chcontext(self.ctx): self.set_resources() vserverimpl.setup_done(self.ctx) @@ -335,8 +326,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") @@ -359,8 +351,10 @@ class VServer: raise ex def enter(self): + + state_file = open("/var/run/vservers/%s.ctx" % self.name, "w") self.__do_chroot() - self.__do_chcontext(None) + self.__do_chcontext(state_file) def start(self, wait, runlevel = 3): self.vm_running = True @@ -374,7 +368,7 @@ class VServer: os.setsid() # open state file to record vserver info - state_file = open("/var/run/vservers/%s" % self.name, "w") + 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) @@ -420,19 +414,18 @@ class VServer: pass + def update_resources(self, resources): + + self.config.update(resources) + + # write new values to configuration file + self.__update_config_file(self.config_file, resources) + 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() - if not line: - sys.stderr.write(child_stderr.readline()) - (space, inodes) = line.split() - self.disk_inodes = int(inodes) - self.disk_blocks = int(space) - #(self.disk_inodes, self.disk_blocks) = vduimpl.vdu(self.dir) - - return self.disk_blocks * 1024 + + (self.disk_inodes, self.disk_blocks, size) = vduimpl.vdu(self.dir) + + return size def stop(self, signal = signal.SIGKILL): vserverimpl.killall(self.ctx, signal) diff --git a/python/vserverimpl.c b/python/vserverimpl.c index 4afba2a..0bbd2c1 100644 --- a/python/vserverimpl.c +++ b/python/vserverimpl.c @@ -340,17 +340,6 @@ initvserverimpl(void) PyModule_AddIntConstant(mod, "DLIMIT_INF", (int)CDLIM_INFINITY); PyModule_AddIntConstant(mod, "VC_LIM_KEEP", (int)VC_LIM_KEEP); - PyModule_AddIntConstant(mod, "RLIMIT_CPU", (int)RLIMIT_CPU); - PyModule_AddIntConstant(mod, "RLIMIT_RSS", (int)RLIMIT_RSS); - PyModule_AddIntConstant(mod, "RLIMIT_NPROC", (int)RLIMIT_NPROC); - PyModule_AddIntConstant(mod, "RLIMIT_NOFILE", (int)RLIMIT_NOFILE); - PyModule_AddIntConstant(mod, "RLIMIT_MEMLOCK", (int)RLIMIT_MEMLOCK); - PyModule_AddIntConstant(mod, "RLIMIT_AS", (int)RLIMIT_AS); - PyModule_AddIntConstant(mod, "RLIMIT_LOCKS", (int)RLIMIT_LOCKS); - - PyModule_AddIntConstant(mod, "RLIMIT_SIGPENDING", (int)RLIMIT_SIGPENDING); - PyModule_AddIntConstant(mod, "RLIMIT_MSGQUEUE", (int)RLIMIT_MSGQUEUE); - PyModule_AddIntConstant(mod, "VLIMIT_NSOCK", (int)VLIMIT_NSOCK); PyModule_AddIntConstant(mod, "VLIMIT_OPENFD", (int)VLIMIT_OPENFD); PyModule_AddIntConstant(mod, "VLIMIT_ANON", (int)VLIMIT_ANON); diff --git a/util-vserver.spec b/util-vserver.spec index 27be578..4b4bb4b 100644 --- a/util-vserver.spec +++ b/util-vserver.spec @@ -17,7 +17,7 @@ %define name util-vserver %define version 0.30.208 -%define release 19%{?pldistro:.%{pldistro}}%{?date:.%{date}} +%define release 17%{?pldistro:.%{pldistro}}%{?date:.%{date}} %define _without_dietlibc 1 %define _without_xalan 1