setting runlevels was set to the wrong path. FIXED
[util-vserver-pl.git] / python / vserver.py
index e3748f4..8aa410e 100644 (file)
@@ -187,18 +187,39 @@ class VServer:
 
         return update
 
 
         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")
@@ -267,7 +288,6 @@ class VServer:
             block_usage = self.disk_blocks
             inode_usage = self.disk_inodes
 
             block_usage = self.disk_blocks
             inode_usage = self.disk_inodes
 
-
         try:
             vserverimpl.setdlimit(self.dir,
                                   self.ctx,
         try:
             vserverimpl.setdlimit(self.dir,
                                   self.ctx,
@@ -349,40 +369,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:
@@ -391,18 +418,25 @@ 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, wait, runlevel = 3):
-        self.vm_running = True
 
 
-        child_pid = os.fork()
-        if child_pid == 0:
+    def start(self, runlevel = 3):
+
+        if (os.fork() != 0):
+            # Parent should just return.
+            self.vm_running = True
+            return
+        else:
             # child process
             try:
             # child process
             try:
+                # so we don't chcontext with priv'ed fds
+                close_nonstandard_fds()
+
                 # get a new session
                 os.setsid()
 
                 # get a new session
                 os.setsid()
 
@@ -420,37 +454,38 @@ class VServer:
 
                 self.config.cache_it()
                 self.__do_chroot()
 
                 self.config.cache_it()
                 self.__do_chroot()
+                removed = self.__cleanvar()
+
                 log = open("/var/log/boot.log", "a", 0)
                 if log.fileno() != 1:
                     os.dup2(log.fileno(), 1)
                 os.dup2(1, 2)
 
                 log = open("/var/log/boot.log", "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" %
                 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)
                 for cmd in self.INITSCRIPTS:
                 # 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,
+                    try:
+                        # enter vserver context
+                        arg_subst = { 'runlevel': runlevel }
+                        cmd_args = [cmd[0]] + map(lambda x: x % arg_subst,
                                                    cmd[1:])
                                                    cmd[1:])
-                         print >>log, "executing '%s'" % " ".join(cmd_args)
-                         os.spawnvp(os.P_NOWAIT,cmd[0],cmd_args)
-                     except:
-                         print >>log, traceback.format_exc()
-                         os._exit(1)
+                        if os.path.isfile(cmd[0]):                         
+                            print >>log, "executing '%s'" % " ".join(cmd_args)
+                            os.spawnvp(os.P_NOWAIT,cmd[0],cmd_args)
+                    except:
+                        print >>log, traceback.format_exc()
 
             # we get here due to an exception in the top-level child process
             except Exception, ex:
                 self.log(traceback.format_exc())
             os._exit(0)
 
 
             # we get here due to an exception in the top-level child process
             except Exception, ex:
                 self.log(traceback.format_exc())
             os._exit(0)
 
-        # parent process
-        return child_pid
-
-    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. """
@@ -458,6 +493,13 @@ class VServer:
         pass
 
     def init_disk_info(self):
         pass
 
     def init_disk_info(self):
+        try:
+            dlimit = vserverimpl.getdlimit(self.dir, self.ctx)
+            self.disk_blocks = dlimit[0]
+            self.disk_inodes = dlimit[2]
+            return self.disk_blocks * 1024
+        except Exception, e:
+            pass
         cmd = "/usr/sbin/vdu --script --space --inodes --blocksize 1024 --xid %d %s" % (self.ctx, self.dir)
         p = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE,
                              stdout=subprocess.PIPE, stderr=subprocess.PIPE,
         cmd = "/usr/sbin/vdu --script --space --inodes --blocksize 1024 --xid %d %s" % (self.ctx, self.dir)
         p = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE,
                              stdout=subprocess.PIPE, stderr=subprocess.PIPE,
@@ -506,3 +548,12 @@ def create(vm_name, static = False, ctor = VServer):
     vm_id = pwd.getpwnam(vm_name)[2]
 
     return ctor(vm_name, vm_id)
     vm_id = pwd.getpwnam(vm_name)[2]
 
     return ctor(vm_name, vm_id)
+
+
+def close_nonstandard_fds():
+    """Close all open file descriptors other than 0, 1, and 2."""
+    _SC_OPEN_MAX = 4
+    for fd in range(3, os.sysconf(_SC_OPEN_MAX)):
+        try: os.close(fd)
+        except OSError: pass  # most likely an fd that isn't open
+