Fix handling of over-quota condition
[util-vserver.git] / python / vserver.py
index 7d1364f..264aee2 100644 (file)
@@ -28,11 +28,6 @@ FLAGS_HIDEINFO = 32
 FLAGS_ULIMIT = 64
 FLAGS_NAMESPACE = 128
 
-# default values for new vserver scheduler
-SCHED_TOKENS_MIN = 50
-SCHED_TOKENS_MAX = 100
-SCHED_TOKENS = 100
-SCHED_INTERVAL = 1000
 
               
 class VServer:
@@ -40,7 +35,7 @@ class VServer:
     INITSCRIPTS = [('/etc/rc.vinit', 'start'),
                    ('/etc/rc.d/rc', '%(runlevel)d')]
 
-    def __init__(self, name):
+    def __init__(self, name, vm_running = False, resources = {}):
 
         self.name = name
         self.config_file = "/etc/vservers/%s.conf" % name
@@ -58,6 +53,8 @@ class VServer:
             self.flags |= FLAGS_NPROC
         self.remove_caps = ~vserverimpl.CAP_SAFE;
         self.ctx = int(self.config["S_CONTEXT"])
+        self.vm_running = vm_running
+        self.resources = resources
 
     config_var_re = re.compile(r"^ *([A-Z_]+)=(.*)\n?$", re.MULTILINE)
 
@@ -84,7 +81,7 @@ class VServer:
             (key, val) = m.groups()
             newval = todo.pop(key, None)
             if newval != None:
-                data = data[:m.start(2)] + newval + data[m.end(2):]
+                data = data[:m.start(2)] + str(newval) + data[m.end(2):]
                 changed = True
         for (newkey, newval) in todo.items():
             data += "%s=%s\n" % (newkey, newval)
@@ -111,30 +108,35 @@ class VServer:
 
     def __do_chroot(self):
 
-        return os.chroot(self.dir)
+        os.chroot(self.dir)
+        os.chdir("/")
 
     def set_disklimit(self, block_limit):
 
-        # block_limit is in kB, get_disk_usage() must have been called
-        if self.disk_usage_set:
+        # block_limit is in kB
+        over_limit = False
+        if self.vm_running:
             block_usage = vserverimpl.DLIMIT_KEEP
             inode_usage = vserverimpl.DLIMIT_KEEP
         else:
+            # init_disk_info() must have been called to get usage values
             block_usage = self.disk_blocks
             inode_usage = self.disk_inodes
             if block_limit < block_usage:
-                raise Exception, ("%s disk usage (%u blocks) > limit (%u)" %
-                                  (self.name, block_usage, block_limit))
-            self.disk_usage_set = True
+                over_limit = True
 
         vserverimpl.setdlimit(self.dir,
                               self.ctx,
                               block_usage,
                               block_limit,
                               inode_usage,
-                              -1,  # inode limit
+                              vserverimpl.DLIMIT_INF,  # inode limit
                               2)   # %age reserved for root
 
+        if over_limit:
+            raise Exception, ("%s disk usage (%u blocks) > limit (%u)" %
+                              (self.name, block_usage, block_limit))
+
     def get_disklimit(self):
 
         try:
@@ -148,39 +150,14 @@ class VServer:
 
         return blocktotal
 
-    def set_sched(self, shares = 32, besteffort = True):
-        # for the old CKRM scheduler
-        if cpulimit.checkckrm() is True:
-            cpulimit.cpuinit()
-            cpulimit.vs2ckrm_on(self.name)
-            try:
-                cpulimit.cpulimit(self.name,shares)
-            except OSError, ex:
-                if ex.errno == 22:
-                    print "invalid shares argument"
-                    # should re-raise exception?!
+    def set_sched(self, cpu_share):
 
-        # for the new vserver scheduler
-        else:
-            global SCHED_TOKENS_MIN, SCHED_TOKENS_MAX, SCHED_TOKENS, SCHED_INTERVAL
-            tokensmin = SCHED_TOKENS_MIN
-            tokensmax = SCHED_TOKENS_MAX
-            tokens    = SCHED_TOKENS
-            interval  = SCHED_INTERVAL
-            fillrate = shares
-
-            if besteffort is True:
-                cpuguaranteed = 0
-            else:
-                cpuguaranteed = 1
+        if cpu_share == int(self.config.get("CPULIMIT", -1)):
+            return
 
-            try:
-                vserverimpl.setsched(self.ctx,fillrate,interval,tokens,tokensmin,tokensmax,cpuguaranteed)
-            except OSError, ex:
-                if ex.errno == 22:
-                    print "kernel does not support vserver scheduler"
-                else:
-                    raise ex
+        self.__update_config_file(self.config_file, { "CPULIMIT": cpu_share })
+        if self.vm_running:
+            vserverimpl.setsched(self.ctx, cpu_share, True)
 
     def get_sched(self):
         # have no way of querying scheduler right now on a per vserver basis
@@ -273,9 +250,9 @@ class VServer:
 
         return os.fdopen(fd, mode, bufsize)
 
-    def __do_chcontext(self, state_file = None):
+    def __do_chcontext(self, state_file):
 
-        vserverimpl.chcontext(self.ctx)
+        vserverimpl.chcontext(self.ctx, self.resources)
 
         if not state_file:
             return
@@ -331,8 +308,7 @@ class VServer:
 
     def start(self, wait, runlevel = 3):
 
-        # XXX - temporary hack
-        self.set_disklimit(int(self.config.get("DISKLIMIT", 5000000)))
+        self.vm_running = True
 
         child_pid = os.fork()
         if child_pid == 0:
@@ -410,19 +386,8 @@ class VServer:
         # write new values to configuration file
         self.__update_config_file(self.config_file, resources)
 
-        # disklimit can be applied without a process in context
-        disklimit = resources.get("DISKLIMIT", 0)
-        if disklimit:
-            self.set_disklimit(disklimit)
-
-        #
-        # Figure out if any processes are active in context, apply new
-        # values if there are.
-        #
-
     def init_disk_info(self):
 
         (self.disk_inodes, self.disk_blocks, size) = vduimpl.vdu(self.dir)
-        self.disk_usage_set = False
 
         return size