Update CPU token buckets of running vserver
[util-vserver-pl.git] / python / vserver.py
index c201bc7..39275de 100644 (file)
@@ -17,7 +17,6 @@ import resource
 import vserverimpl
 import cpulimit, bwlimit
 
 import vserverimpl
 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 VLIMIT_NSOCK
 from vserverimpl import DLIMIT_INF
 from vserverimpl import VC_LIM_KEEP
 from vserverimpl import VLIMIT_NSOCK
@@ -135,7 +134,7 @@ class VServer:
     INITSCRIPTS = [('/etc/rc.vinit', 'start'),
                    ('/etc/rc.d/rc', '%(runlevel)d')]
 
     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 = None, logfile=None):
 
         self.name = name
         self.rlimits_changed = False
 
         self.name = name
         self.rlimits_changed = False
@@ -151,6 +150,18 @@ class VServer:
         if vm_running == None:
             vm_running = self.is_running()
         self.vm_running = vm_running
         if vm_running == None:
             vm_running = self.is_running()
         self.vm_running = vm_running
+        self.logfile = logfile
+
+    # inspired from nodemanager's logger
+    def log(self,msg):
+        if self.logfile:
+            try:
+                fd = os.open(self.logfile,os.O_WRONLY | os.O_CREAT | os.O_APPEND, 0600)
+                if not msg.endswith('\n'): msg += '\n'
+                os.write(fd, '%s: %s' % (time.asctime(time.gmtime()), msg))
+                os.close(fd)
+            except:
+                print '%s: (%s failed to open) %s'%(time.asctime(time.gmtime()),self.logfile,msg)
 
     def have_limits_changed(self):
         return self.rlimits_changed
 
     def have_limits_changed(self):
         return self.rlimits_changed
@@ -166,13 +177,13 @@ class VServer:
             if old_minimum != VC_LIM_KEEP and old_minimum <> minimum: changed = True
             self.rlimits_changed = self.rlimits_changed or changed 
         except OSError, e:
             if old_minimum != VC_LIM_KEEP and old_minimum <> minimum: changed = True
             self.rlimits_changed = self.rlimits_changed or changed 
         except OSError, e:
-            if self.is_running(): print "Unexpected error with getrlimit for running context %d" % self.ctx
+            if self.is_running(): self.log("Unexpected error with getrlimit for running context %d" % self.ctx)
 
         resource_type = RLIMITS[type]
         try:
             ret = vserverimpl.setrlimit(self.ctx,resource_type,hard,soft,minimum)
         except OSError, e:
 
         resource_type = RLIMITS[type]
         try:
             ret = vserverimpl.setrlimit(self.ctx,resource_type,hard,soft,minimum)
         except OSError, e:
-            if self.is_running(): print "Unexpected error with setrlimit for running context %d" % self.ctx
+            if self.is_running(): self.log("Unexpected error with setrlimit for running context %d" % self.ctx)
 
     def set_rlimit_config(self,type,hard,soft,minimum):
         """Generic set resource limit function for vserver"""
 
     def set_rlimit_config(self,type,hard,soft,minimum):
         """Generic set resource limit function for vserver"""
@@ -191,7 +202,7 @@ class VServer:
         try:
             ret = vserverimpl.getrlimit(self.ctx,resource_type)
         except OSError, e:
         try:
             ret = vserverimpl.getrlimit(self.ctx,resource_type)
         except OSError, e:
-            print "Unexpected error with getrlimit for context %d" % self.ctx
+            self.log("Unexpected error with getrlimit for context %d" % self.ctx)
             ret = self.get_rlimit_config(type)
         return ret
 
             ret = self.get_rlimit_config(type)
         return ret
 
@@ -271,7 +282,7 @@ class VServer:
             try:
                 vserverimpl.unsetdlimit(self.dir, self.ctx)
             except OSError, e:
             try:
                 vserverimpl.unsetdlimit(self.dir, self.ctx)
             except OSError, e:
-                print "Unexpected error with unsetdlimit for context %d" % self.ctx
+                self.log("Unexpected error with unsetdlimit for context %d" % self.ctx)
             return
 
         if self.vm_running:
             return
 
         if self.vm_running:
@@ -292,7 +303,7 @@ class VServer:
                                   vserverimpl.DLIMIT_INF,  # inode limit
                                   2)   # %age reserved for root
         except OSError, e:
                                   vserverimpl.DLIMIT_INF,  # inode limit
                                   2)   # %age reserved for root
         except OSError, e:
-            print "Unexpected error with setdlimit for context %d" % self.ctx
+            self.log("Unexpected error with setdlimit for context %d" % self.ctx)
 
 
         self.config.update('dlimits/0/space_total', block_limit)
 
 
         self.config.update('dlimits/0/space_total', block_limit)
@@ -313,25 +324,23 @@ class VServer:
 
         return block_limit
 
 
         return block_limit
 
-    def set_sched_config(self, cpu_share, sched_flags):
+    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. """
 
 
         """ Write current CPU scheduler parameters to the 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-rate', cpu_min)
         self.config.update('sched/fill-rate2', cpu_share)
         self.config.update('sched/fill-rate2', cpu_share)
-        self.config.update('sched/fill-rate', cpu_guaranteed)
-
-        if self.vm_running:
-            self.set_sched(cpu_share, sched_flags)
+        if cpu_share == 0:
+            self.config.unset('sched/idle-time')
+        
+        if self.is_running():
+            self.set_sched(cpu_min, cpu_share)
 
 
-    def set_sched(self, cpu_share, sched_flags = 0):
+    def set_sched(self, cpu_min, cpu_share):
         """ Update kernel CPU scheduling parameters for this context. """
         """ Update kernel CPU scheduling parameters for this context. """
-        vserverimpl.setsched(self.ctx, cpu_share, sched_flags)
+        vserverimpl.setsched(self.ctx, cpu_min, cpu_share)
 
     def get_sched(self):
         # have no way of querying scheduler right now on a per vserver basis
 
     def get_sched(self):
         # have no way of querying scheduler right now on a per vserver basis
@@ -369,7 +378,7 @@ class VServer:
             self.set_resources()
             vserverimpl.setup_done(self.ctx)
 
             self.set_resources()
             vserverimpl.setup_done(self.ctx)
 
-    def __prep(self, runlevel, log):
+    def __prep(self, runlevel):
 
         """ Perform all the crap that the vserver script does before
         actually executing the startup scripts. """
 
         """ Perform all the crap that the vserver script does before
         actually executing the startup scripts. """
@@ -391,9 +400,7 @@ class VServer:
                 os.unlink(f)
 
         # set the initial runlevel
                 os.unlink(f)
 
         # set the initial runlevel
-        f = open(RUNDIR + "/utmp", "w")
-        vserverimpl.setrunlevel(f, runlevel)
-        f.close()
+        vserverimpl.setrunlevel(RUNDIR + "/utmp", runlevel)
 
         # mount /proc and /dev/pts
         self.__do_mount("none", self.dir, "/proc", "proc")
 
         # mount /proc and /dev/pts
         self.__do_mount("none", self.dir, "/proc", "proc")
@@ -434,19 +441,19 @@ class VServer:
                 if fd != 0:
                     os.dup2(fd, 0)
                     os.close(fd)
                 if fd != 0:
                     os.dup2(fd, 0)
                     os.close(fd)
+                # perform pre-init cleanup
+                self.__prep(runlevel)
+
                 self.config.cache_it()
                 self.__do_chroot()
                 self.config.cache_it()
                 self.__do_chroot()
-                log = open("/var/log/boot.log", "w", 0)
+                log = open("/var/log/boot.log", "a", 0)
                 if log.fileno() != 1:
                     os.dup2(log.fileno(), 1)
                 os.dup2(1, 2)
 
                 print >>log, ("%s: starting the virtual server %s" %
                               (time.asctime(time.gmtime()), self.name))
                 if log.fileno() != 1:
                     os.dup2(log.fileno(), 1)
                 os.dup2(1, 2)
 
                 print >>log, ("%s: starting the virtual server %s" %
                               (time.asctime(time.gmtime()), self.name))
-
-                # perform pre-init cleanup
-                self.__prep(runlevel, log)
-
                 # execute each init script in turn
                 # XXX - we don't support all scripts that vserver script does
                 self.__do_chcontext(state_file)
                 # execute each init script in turn
                 # XXX - we don't support all scripts that vserver script does
                 self.__do_chcontext(state_file)
@@ -459,12 +466,12 @@ class VServer:
                          print >>log, "executing '%s'" % " ".join(cmd_args)
                          os.spawnvp(os.P_NOWAIT,cmd[0],cmd_args)
                      except:
                          print >>log, "executing '%s'" % " ".join(cmd_args)
                          os.spawnvp(os.P_NOWAIT,cmd[0],cmd_args)
                      except:
-                         traceback.print_exc()
+                         print >>log, traceback.format_exc()
                          os._exit(1)
 
             # we get here due to an exception in the top-level child process
             except Exception, ex:
                          os._exit(1)
 
             # we get here due to an exception in the top-level child process
             except Exception, ex:
-                traceback.print_exc()
+                self.log(traceback.format_exc())
             os._exit(0)
 
         # parent process
             os._exit(0)
 
         # parent process