X-Git-Url: http://git.onelab.eu/?p=util-vserver-pl.git;a=blobdiff_plain;f=python%2Fvserver.py;h=55d78f044209ec79104fb79ed75c787c501cec36;hp=44341a6c841793f2d11ad9fef30ec78cb5980e6b;hb=a6e1134d8bdb41b0146cdac83e4e82909e74cb47;hpb=417e8eb25ca47ac9b92c05393eaa131e7e083fd9 diff --git a/python/vserver.py b/python/vserver.py index 44341a6..55d78f0 100644 --- a/python/vserver.py +++ b/python/vserver.py @@ -12,6 +12,7 @@ import sys import time import traceback import subprocess +import commands import resource import vserverimpl @@ -41,6 +42,8 @@ RLIMITS = { "NSOCK": VLIMIT_NSOCK, "ANON": VLIMIT_ANON, "SHMEM": VLIMIT_SHMEM} +CPU_SHARE_MULT = 1024 + # add in the platform supported rlimits for entry in resource.__dict__.keys(): if entry.find("RLIMIT_")==0: @@ -52,7 +55,6 @@ for entry in resource.__dict__.keys(): class NoSuchVServer(Exception): pass - class VServerConfig: def __init__(self, name, directory): self.name = name @@ -129,26 +131,6 @@ class VServerConfig: os.path.walk(self.dir, add_to_cache, self.cache) -def adjust_lim(goal, curr): - gh = goal[0] - gs = goal[1] - gm = goal[2] - soft = curr[0] - hard = curr[1] - if gm != VC_LIM_KEEP: - if gm > soft or gm == resource.RLIM_INFINITY: - soft = gm - if gm > hard or gm == resource.RLIM_INFINITY: - hard = gm - if gs != VC_LIM_KEEP: - if gs > soft or gs == resource.RLIM_INFINITY: - soft = gs - if gh != VC_LIM_KEEP: - if gh > hard or gh == resource.RLIM_INFINITY: - hard = gh - return (soft, hard) - - class VServer: INITSCRIPTS = [('/etc/rc.vinit', 'start'), @@ -162,7 +144,7 @@ class VServer: 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.remove_caps = ~vserverimpl.CAP_SAFE; + #self.remove_caps = ~vserverimpl.CAP_SAFE; if vm_id == None: vm_id = int(self.config.get('context')) self.ctx = vm_id @@ -201,10 +183,6 @@ class VServer: resource_type = RLIMITS[type] try: vserverimpl.setrlimit(self.ctx, resource_type, hard, soft, min) - if hasattr(resource, 'RLIMIT_' + type): - lim = resource.getrlimit(resource_type) - lim = adjust_lim((hard, soft, min), lim) - resource.setrlimit(resource_type, lim) except OSError, e: self.log("Error: setrlimit(%d, %s, %d, %d, %d): %s" % (self.ctx, type.lower(), hard, soft, min, e)) @@ -224,6 +202,9 @@ class VServer: def set_capabilities_config(self, capabilities): bcaps = self.get_bcaps_from_capabilities(capabilities) ccaps = self.get_ccaps_from_capabilities(capabilities) + if len(bcaps) > 0: + bcaps += "," + bcaps += "CAP_NET_RAW" self.config.update('bcapabilities', bcaps) self.config.update('ccapabilities', ccaps) ret = vserverimpl.setbcaps(self.ctx, vserverimpl.text2bcaps(bcaps)) @@ -251,6 +232,7 @@ class VServer: vserverimpl.netadd(self.ctx, a) def set_ipaddresses_config(self, addresses): + return # acb i = 0 for a in addresses.split(","): self.config.update("interfaces/%d/ip" % i, a) @@ -272,6 +254,7 @@ class VServer: def get_ipaddresses(self): # No clean way to do this right now. + self.log("Calling Vserver.get_ipaddresses for slice %s" % self.name) return None def __do_chroot(self): @@ -279,7 +262,6 @@ class VServer: os.chdir("/") def chroot_call(self, fn, *args): - cwd_fd = os.open(".", os.O_RDONLY) try: root_fd = os.open("/", os.O_RDONLY) @@ -301,7 +283,7 @@ class VServer: try: vserverimpl.unsetdlimit(self.dir, self.ctx) except OSError, e: - self.log("Unexpected error with unsetdlimit for context %d: %r" % (self.ctx,e)) + self.log("Unexpected error with unsetdlimit for context %d" % self.ctx) return if self.vm_running: @@ -321,16 +303,15 @@ class VServer: vserverimpl.DLIMIT_INF, # inode limit 2) # %age reserved for root except OSError, e: - self.log("Unexpected error with setdlimit for context %d: %r" % (self.ctx, e)) - + self.log("Unexpected error with setdlimit for context %d" % self.ctx) self.config.update('dlimits/0/space_total', block_limit) def is_running(self): - return vserverimpl.isrunning(self.ctx) + status = subprocess.call(["/usr/sbin/vserver", self.name, "running"], shell=False) + return not status def get_disklimit(self): - try: (self.disk_blocks, block_limit, self.disk_inodes, inode_limit, reserved) = vserverimpl.getdlimit(self.dir, self.ctx) @@ -343,26 +324,28 @@ class VServer: return block_limit def set_sched_config(self, cpu_min, cpu_share): - """ Write current CPU scheduler parameters to the vserver - configuration file. This method does not modify the kernel CPU - scheduling parameters for this context. """ - - self.config.update('sched/fill-rate', cpu_min) - self.config.update('sched/fill-rate2', cpu_share) - if cpu_share == 0: - self.config.unset('sched/idle-time') - + configuration file. Currently, 'cpu_min' is not supported. """ + self.config.update('cgroup/cpu.shares', cpu_share * CPU_SHARE_MULT) if self.is_running(): self.set_sched(cpu_min, cpu_share) def set_sched(self, cpu_min, cpu_share): - """ Update kernel CPU scheduling parameters for this context. """ - vserverimpl.setsched(self.ctx, cpu_min, cpu_share) + """ Update kernel CPU scheduling parameters for this context. + Currently, 'cpu_min' is not supported. """ + try: + cgroup = open('/dev/cgroup/%s/cpu.shares' % name, 'w') + cgroup.write('%s' % (cpu_share * CPU_SHARE_MULT)) + cgroup.close() + except: + pass def get_sched(self): - # have no way of querying scheduler right now on a per vserver basis - return (-1, False) + try: + cpu_share = int(int(self.config.get('cgroup/cpu.shares')) / CPU_SHARE_MULT) + except: + cpu_share = False + return (-1, cpu_share) def set_bwlimit(self, minrate = bwlimit.bwmin, maxrate = None, exempt_min = None, exempt_max = None, @@ -386,71 +369,10 @@ class VServer: return self.chroot_call(open, filename, mode, bufsize) - def __do_chcontext(self, state_file): - - if state_file: - print >>state_file, "%u" % self.ctx - state_file.close() - - if vserverimpl.chcontext(self.ctx, vserverimpl.text2bcaps(self.get_capabilities_config())): - self.set_resources(True) - vserverimpl.setup_done(self.ctx) - - - def __prep(self, runlevel): - - """ Perform all the crap that the vserver script does before - actually executing the startup scripts. """ - - - # set the initial runlevel - vserverimpl.setrunlevel(self.dir + "/var/run/utmp", runlevel) - - # mount /proc and /dev/pts - self.__do_mount("none", self.dir, "/proc", "proc") - # XXX - magic mount options - self.__do_mount("none", self.dir, "/dev/pts", "devpts", 0, "gid=5,mode=0620") - - - def __cleanvar(self): - """ - Clean the /var/ directory so RH startup scripts can run - """ - - RUNDIR = "/var/run" - LOCKDIR = "/var/lock/subsys" - - filter = ["utmp"] - garbage = [] - for topdir in [RUNDIR, LOCKDIR]: - #os.walk() = (dirpath, dirnames, filenames) - for root, dirs, files in os.walk(topdir): - for file in files: - if not file in filter: - garbage.append(root + "/" + file) - - for f in garbage: os.unlink(f) - return garbage - - - def __do_mount(self, *mount_args): - try: - vserverimpl.mount(*mount_args) - except OSError, ex: - if ex.errno == errno.EBUSY: - # assume already mounted - return - raise ex - - def enter(self): - self.config.cache_it() - self.__do_chroot() - self.__do_chcontext(None) - + subprocess.call("/usr/sbin/vserver %s enter" % self.name, shell=True) def start(self, runlevel = 3): - if (os.fork() != 0): # Parent should just return. self.vm_running = True @@ -458,63 +380,14 @@ class VServer: else: # child process try: - # so we don't chcontext with priv'ed fds - close_nonstandard_fds() - - # get a new session - os.setsid() - - # open state file to record vserver info - state_file = open("/var/run/vservers/%s" % self.name, "w") - - # use /dev/null for stdin, /var/log/nm for stdout/err - fd = os.open("/dev/null", os.O_RDONLY) - if fd != 0: - os.dup2(fd, 0) - os.close(fd) - - # perform pre-init cleanup - self.__prep(runlevel) - - self.config.cache_it() - self.__do_chroot() - if not self.is_running(): - removed = self.__cleanvar() - else: - removed = 0 - - log = open("/var/log/nm", "a", 0) - if log.fileno() != 1: - os.dup2(log.fileno(), 1) - os.dup2(1, 2) - - print >>log, ("%s: removing %s" % - (time.asctime(time.gmtime()), removed)) - print >>log, ("%s: starting the virtual server %s" % - (time.asctime(time.gmtime()), self.name)) - # 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: - try: - # enter vserver context - arg_subst = { 'runlevel': runlevel } - cmd_args = [cmd[0]] + map(lambda x: x % arg_subst, - cmd[1:]) - if os.path.isfile(cmd[0]): - print >>log, "executing '%s'" % " ".join(cmd_args) - os.spawnvp(os.P_NOWAIT,cmd[0],cmd_args) - else: - print >>log, "WARNING: could not run %s"%cmd[0] - except: - print >>log, traceback.format_exc() - + subprocess.call("/usr/sbin/vserver %s start" % self.name, + shell=True) # we get here due to an exception in the top-level child process except Exception, ex: self.log(traceback.format_exc()) os._exit(0) - def set_resources(self,setup=False): + def set_resources(self): """ Called when vserver context is entered for first time, should be overridden by subclass. """ @@ -544,17 +417,15 @@ class VServer: (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 def stop(self, signal = signal.SIGKILL): - vserverimpl.killall(self.ctx, signal) self.vm_running = False + subprocess.call("/usr/sbin/vserver %s stop" % self.name, shell=True) def setname(self, slice_id): - '''Set vcVHI_CONTEXT field in kernel to slice_id''' - vserverimpl.setname(self.ctx, slice_id) + pass def getname(self): '''Get vcVHI_CONTEXT field in kernel'''