Don't clean stuff up if it's already running.
[util-vserver-pl.git] / python / vserver.py
index 7652b78..aee6d03 100644 (file)
@@ -129,6 +129,26 @@ class VServerConfig:
         os.path.walk(self.dir, add_to_cache, self.cache)
 
 
         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'),
 class VServer:
 
     INITSCRIPTS = [('/etc/rc.vinit', 'start'),
@@ -181,24 +201,49 @@ class VServer:
             resource_type = RLIMITS[type]
             try:
                 vserverimpl.setrlimit(self.ctx, resource_type, hard, soft, min)
             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))
 
         return update
 
             except OSError, e:
                 self.log("Error: setrlimit(%d, %s, %d, %d, %d): %s"
                          % (self.ctx, type.lower(), hard, soft, min))
 
         return update
 
-    def set_capabilities(self, capabilities):
-        return vserverimpl.setbcaps(self.ctx, vserverimpl.text2bcaps(capabilities))
+    def get_prefix_from_capabilities(self, capabilities, prefix):
+        split_caps = capabilities.split(',')
+        return ",".join(["%s" % (c) for c in split_caps if c.startswith(prefix.upper()) or c.startswith(prefix.lower())])
+
+    def get_bcaps_from_capabilities(self, capabilities):
+        return self.get_prefix_from_capabilities(capabilities, "cap_")
+
+    def get_ccaps_from_capabilities(self, capabilities):
+        return self.get_prefix_from_capabilities(capabilities, "vxc_")
 
     def set_capabilities_config(self, capabilities):
 
     def set_capabilities_config(self, capabilities):
-        self.config.update('bcapabilities', capabilities)
-        self.set_capabilities(capabilities)
+        bcaps = self.get_bcaps_from_capabilities(capabilities)
+        ccaps = self.get_ccaps_from_capabilities(capabilities)
+        self.config.update('bcapabilities', bcaps)
+        self.config.update('ccapabilities', ccaps)
+        ret = vserverimpl.setbcaps(self.ctx, vserverimpl.text2bcaps(bcaps))
+        if ret > 0:
+            return ret
+        return vserverimpl.setccaps(self.ctx, vserverimpl.text2ccaps(ccaps))
 
     def get_capabilities(self):
 
     def get_capabilities(self):
-        return vserverimpl.bcaps2text(vserverimpl.getbcaps(self.ctx))
+        bcaps = vserverimpl.bcaps2text(vserverimpl.getbcaps(self.ctx))
+        ccaps = vserverimpl.ccaps2text(vserverimpl.getccaps(self.ctx))
+        if bcaps and ccaps:
+            ccaps = "," + ccaps
+        return (bcaps + ccaps)
  
     def get_capabilities_config(self):
  
     def get_capabilities_config(self):
-        return self.config.get('bcapabilities', '')
+        bcaps = self.config.get('bcapabilities', '')
+        ccaps = self.config.get('ccapabilities', '')
+        if bcaps and ccaps:
+            ccaps = "," + ccaps
+        return (bcaps + ccaps)
 
     def set_ipaddresses(self, addresses):
         vserverimpl.netremove(self.ctx, "all")
 
     def set_ipaddresses(self, addresses):
         vserverimpl.netremove(self.ctx, "all")
@@ -256,7 +301,7 @@ class VServer:
             try:
                 vserverimpl.unsetdlimit(self.dir, self.ctx)
             except OSError, e:
             try:
                 vserverimpl.unsetdlimit(self.dir, self.ctx)
             except OSError, e:
-                self.log("Unexpected error with unsetdlimit for context %d" % self.ctx)
+                self.log("Unexpected error with unsetdlimit for context %d: %r" % (self.ctx,e))
             return
 
         if self.vm_running:
             return
 
         if self.vm_running:
@@ -276,7 +321,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:
-            self.log("Unexpected error with setdlimit for context %d" % self.ctx)
+            self.log("Unexpected error with setdlimit for context %d: %r" % (self.ctx, e))
 
 
         self.config.update('dlimits/0/space_total', block_limit)
 
 
         self.config.update('dlimits/0/space_total', block_limit)
@@ -348,40 +393,47 @@ class VServer:
             state_file.close()
 
         if vserverimpl.chcontext(self.ctx, vserverimpl.text2bcaps(self.get_capabilities_config())):
             state_file.close()
 
         if vserverimpl.chcontext(self.ctx, vserverimpl.text2bcaps(self.get_capabilities_config())):
-            self.set_resources()
+            self.set_resources(True)
             vserverimpl.setup_done(self.ctx)
 
             vserverimpl.setup_done(self.ctx)
 
+
     def __prep(self, runlevel):
 
         """ Perform all the crap that the vserver script does before
         actually executing the startup scripts. """
 
     def __prep(self, runlevel):
 
         """ Perform all the crap that the vserver script does before
         actually executing the startup scripts. """
 
-        # remove /var/run and /var/lock/subsys files
-        # but don't remove utmp from the top-level /var/run
-        RUNDIR = "/var/run"
-        LOCKDIR = "/var/lock/subsys"
-        filter_fn = lambda fs: filter(lambda f: f != 'utmp', fs)
-        garbage = reduce((lambda (out, ff), (dir, subdirs, files):
-                          (out + map((dir + "/").__add__, ff(files)),
-                           lambda fs: fs)),
-                         list(os.walk(RUNDIR)),
-                         ([], filter_fn))[0]
-        garbage += filter(os.path.isfile, map((LOCKDIR + "/").__add__,
-                                              os.listdir(LOCKDIR)))
-        if False:
-            for f in garbage:
-                os.unlink(f)
 
         # set the initial runlevel
 
         # set the initial runlevel
-        vserverimpl.setrunlevel(RUNDIR + "/utmp", 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")
 
 
         # 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 __do_mount(self, *mount_args):
 
 
+    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:
         try:
             vserverimpl.mount(*mount_args)
         except OSError, ex:
@@ -390,11 +442,13 @@ class VServer:
                 return
             raise ex
 
                 return
             raise ex
 
+
     def enter(self):
         self.config.cache_it()
         self.__do_chroot()
         self.__do_chcontext(None)
 
     def enter(self):
         self.config.cache_it()
         self.__do_chroot()
         self.__do_chcontext(None)
 
+
     def start(self, runlevel = 3):
 
         if (os.fork() != 0):
     def start(self, runlevel = 3):
 
         if (os.fork() != 0):
@@ -413,7 +467,7 @@ class VServer:
                 # open state file to record vserver info
                 state_file = open("/var/run/vservers/%s" % self.name, "w")
 
                 # open state file to record vserver info
                 state_file = open("/var/run/vservers/%s" % self.name, "w")
 
-                # use /dev/null for stdin, /var/log/boot.log for stdout/err
+                # 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)
                 fd = os.open("/dev/null", os.O_RDONLY)
                 if fd != 0:
                     os.dup2(fd, 0)
@@ -424,13 +478,18 @@ class VServer:
 
                 self.config.cache_it()
                 self.__do_chroot()
 
                 self.config.cache_it()
                 self.__do_chroot()
-                log = open("/var/log/boot.log", "a", 0)
+                if not self.is_running():
+                    removed = self.__cleanvar()
+
+                log = open("/var/log/nm", "a", 0)
                 if log.fileno() != 1:
                     os.dup2(log.fileno(), 1)
                 os.dup2(1, 2)
 
                 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" %
                 print >>log, ("%s: starting the virtual server %s" %
-                              (time.asctime(time.gmtime()), self.name))
+                                (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)
                 # execute each init script in turn
                 # XXX - we don't support all scripts that vserver script does
                 self.__do_chcontext(state_file)
@@ -443,6 +502,8 @@ class VServer:
                         if os.path.isfile(cmd[0]):                         
                             print >>log, "executing '%s'" % " ".join(cmd_args)
                             os.spawnvp(os.P_NOWAIT,cmd[0],cmd_args)
                         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()
 
                     except:
                         print >>log, traceback.format_exc()
 
@@ -451,7 +512,7 @@ class VServer:
                 self.log(traceback.format_exc())
             os._exit(0)
 
                 self.log(traceback.format_exc())
             os._exit(0)
 
-    def set_resources(self):
+    def set_resources(self,setup=False):
 
         """ Called when vserver context is entered for first time,
         should be overridden by subclass. """
 
         """ Called when vserver context is entered for first time,
         should be overridden by subclass. """
@@ -460,7 +521,7 @@ class VServer:
 
     def init_disk_info(self):
         try:
 
     def init_disk_info(self):
         try:
-            dlimit = vserver.getdlimit(self.dir, self.ctx)
+            dlimit = vserverimpl.getdlimit(self.dir, self.ctx)
             self.disk_blocks = dlimit[0]
             self.disk_inodes = dlimit[2]
             return self.disk_blocks * 1024
             self.disk_blocks = dlimit[0]
             self.disk_inodes = dlimit[2]
             return self.disk_blocks * 1024