redirect the output of the initscripts (rc & rc.vinit) + try to detach
authorThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Fri, 18 Jun 2010 15:48:45 +0000 (15:48 +0000)
committerThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Fri, 18 Jun 2010 15:48:45 +0000 (15:48 +0000)
python/vserver.py

index 612e503..31361ce 100644 (file)
@@ -133,7 +133,8 @@ class VServerConfig:
 
 class VServer:
 
-    INITSCRIPTS = [('/etc/rc.vinit', 'start'),
+    # adding the sliver name is for helping in the forensics 
+    INITSCRIPTS = [('/etc/rc.vinit', 'start', '%(name)s'),
                    ('/etc/rc.d/rc', '%(runlevel)d')]
 
     def __init__(self, name, vm_id = None, vm_running = None, logfile=None):
@@ -154,12 +155,16 @@ class VServer:
         self.logfile = logfile
 
     # inspired from nodemanager's logger
+    def log_in_file (self, fd, msg):
+        if not msg: msg="\n"
+        if not msg.endswith('\n'): msg += '\n'
+        os.write(fd, '%s: %s' % (time.asctime(time.gmtime()), msg))
+
     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))
+                self.log_in_file(fd,msg)
                 os.close(fd)
             except:
                 print '%s: (%s failed to open) %s'%(time.asctime(time.gmtime()),self.logfile,msg)
@@ -372,36 +377,48 @@ class VServer:
     def enter(self):
         subprocess.call("/usr/sbin/vserver %s enter" % self.name, shell=True)
 
+    # detach the process that triggers the initscripts
+    # after http://code.activestate.com/recipes/278731/
     def start(self, runlevel = 3):
-        if (os.fork() != 0):
+        if os.fork() != 0:
             # Parent should just return.
             self.vm_running = True
             return
         else:
-            # child process
+            os.setsid()
+            # first child process: fork again
+            if os.fork() != 0:
+                os._exit(0)    # Exit parent (the first child) of the second child.
+            # the grandson is the working one
+            os.chdir('/')
+            os.umask(0)
             try:
-                subprocess.call("/usr/sbin/vserver %s start" % self.name, 
-                                shell=True)
+                # start the vserver
+                subprocess.call(["/usr/sbin/vserver",self.name,"start"])
 
                 # execute initscripts
-                for cmd in self.INITSCRIPTS:
+                for cmd_to_expand in self.INITSCRIPTS:
+                    # enter vserver context
+                    expand = { 'runlevel': runlevel,
+                               'name': self.name, }
+                    cmd = [ x % expand for x in cmd_to_expand ]
+                    cmd_name = os.path.basename(cmd[0])
+                    cmd_file = "/vservers/" + self.name + cmd[0]
+                    if not os.path.isfile(cmd_file):
+                        self.log("WARNING: could not find %s for %s" % (cmd_file, self.name))
+                        break
+                    self.log("executing %r" % cmd)
                     try:
-                        # enter vserver context
-                        arg_subst = { 'runlevel': runlevel }
-                        cmd_args = [cmd[0]] + map(lambda x: x % arg_subst, cmd[1:])
-                        # add vserver name as the last command argument
-                        cmd_args += [self.name]
-                        cmd_file = "/vservers/" + self.name + cmd[0]
-                        self.log(cmd_file)
-                        if os.path.isfile(cmd_file):
-                            self.log("executing '%s'" % " ".join(cmd_args))
-                            self.chroot_call(subprocess.call, " ".join(cmd_args), shell=True)
-                        else:
-                            self.log("WARNING: could not run %s on %s" % (cmd[0], self.name))
-                    except:
-                        self.log(traceback.format_exc())
-
-            # we get here due to an exception in the top-level child process
+                        logname='/vservers/%s/var/log/%s'%(self.name,cmd_name)
+                        log_fd=os.open(logname,os.O_WRONLY | os.O_CREAT | os.O_APPEND, 0600)
+                        self.log_in_file(log_fd,"Running %r into %s"%(cmd,logname))
+                        self.chroot_call(subprocess.call,cmd,
+                                         stdout=log_fd,stderr=subprocess.STDOUT,
+                                         close_fds=True)
+                    except:  self.log(traceback.format_exc())
+                    finally: os.close(log_fd)
+
+            # we get here due to an exception in the grandson process
             except Exception, ex:
                 self.log(traceback.format_exc())
             os._exit(0)