Browse Source

[trac800] Actually starting the creator

Michal 'vorner' Vaner 13 years ago
parent
commit
9517f61cb8

+ 9 - 0
src/bin/bind10/bind10_messages.mes

@@ -189,3 +189,12 @@ the given file number.
 Either sending or receiving data from the socket creator failed with the given
 Either sending or receiving data from the socket creator failed with the given
 error. The creator probably crashed or some serious OS-level problem happened,
 error. The creator probably crashed or some serious OS-level problem happened,
 as the communication happens only on local host.
 as the communication happens only on local host.
+
+% BIND10_SOCKCREATOR_CRASHED the socket creator crashed
+The socket creator terminated unexpectadly. It is not possible to restart it
+(because the boss already gave up root privileges), so the system is going
+to terminate.
+
+% BIND10_SOCKCREATOR_KILL killing the socket creator
+The socket creator is being terminated the aggressive way, by sending it
+sigkill. This should not happen usually.

+ 33 - 1
src/bin/bind10/bind10_src.py.in

@@ -67,6 +67,7 @@ import isc.util.process
 import isc.net.parse
 import isc.net.parse
 import isc.log
 import isc.log
 from bind10_messages import *
 from bind10_messages import *
+import bind10.sockcreator
 
 
 isc.log.init("b10-boss")
 isc.log.init("b10-boss")
 logger = isc.log.Logger("boss")
 logger = isc.log.Logger("boss")
@@ -248,6 +249,7 @@ class BoB:
         self.config_filename = config_filename
         self.config_filename = config_filename
         self.cmdctl_port = cmdctl_port
         self.cmdctl_port = cmdctl_port
         self.brittle = brittle
         self.brittle = brittle
+        self.sockcreator = None
 
 
     def config_handler(self, new_config):
     def config_handler(self, new_config):
         # If this is initial update, don't do anything now, leave it to startup
         # If this is initial update, don't do anything now, leave it to startup
@@ -333,6 +335,20 @@ class BoB:
                                                             "Unknown command")
                                                             "Unknown command")
         return answer
         return answer
 
 
+    def start_creator(self):
+        self.curproc = 'b10-sockcreator'
+        self.sockcreator = bind10.sockcreator.Creator("@@LIBEXECDIR@@:" +
+                                                      os.environ['PATH'])
+
+    def stop_creator(self, kill=False):
+        if self.sockcreator is None:
+            return
+        if kill:
+            self.sockcreator.kill()
+        else:
+            self.sockcreator.terminate()
+        self.sockcreator = None
+
     def kill_started_processes(self):
     def kill_started_processes(self):
         """
         """
             Called as part of the exception handling when a process fails to
             Called as part of the exception handling when a process fails to
@@ -341,6 +357,8 @@ class BoB:
         """
         """
         logger.info(BIND10_KILLING_ALL_PROCESSES)
         logger.info(BIND10_KILLING_ALL_PROCESSES)
 
 
+        self.stop_creator(True)
+
         for pid in self.processes:
         for pid in self.processes:
             logger.info(BIND10_KILL_PROCESS, self.processes[pid].name)
             logger.info(BIND10_KILL_PROCESS, self.processes[pid].name)
             self.processes[pid].process.kill()
             self.processes[pid].process.kill()
@@ -571,6 +589,11 @@ class BoB:
             Starts up all the processes.  Any exception generated during the
             Starts up all the processes.  Any exception generated during the
             starting of the processes is handled by the caller.
             starting of the processes is handled by the caller.
         """
         """
+        # The socket creator first, as it is the only thing that needs root
+        self.start_creator()
+        # TODO: Once everything uses the socket creator, we can drop root
+        # privileges right now
+
         c_channel_env = self.c_channel_env
         c_channel_env = self.c_channel_env
         self.start_msgq(c_channel_env)
         self.start_msgq(c_channel_env)
         self.start_cfgmgr(c_channel_env)
         self.start_cfgmgr(c_channel_env)
@@ -660,6 +683,8 @@ class BoB:
         self.cc_session.group_sendmsg(cmd, "Zonemgr", "Zonemgr")
         self.cc_session.group_sendmsg(cmd, "Zonemgr", "Zonemgr")
         self.cc_session.group_sendmsg(cmd, "Stats", "Stats")
         self.cc_session.group_sendmsg(cmd, "Stats", "Stats")
         self.cc_session.group_sendmsg(cmd, "StatsHttpd", "StatsHttpd")
         self.cc_session.group_sendmsg(cmd, "StatsHttpd", "StatsHttpd")
+        # Terminate the creator last
+        self.stop_creator()
 
 
     def stop_process(self, process, recipient):
     def stop_process(self, process, recipient):
         """
         """
@@ -746,7 +771,14 @@ class BoB:
                 # XXX: should be impossible to get any other error here
                 # XXX: should be impossible to get any other error here
                 raise
                 raise
             if pid == 0: break
             if pid == 0: break
-            if pid in self.processes:
+            if self.sockcreator is not None and self.sockcreator.pid() == pid:
+                # This is the socket creator, started and terminated
+                # differently. This can't be restarted.
+                if self.runnable:
+                    logger.fatal(BIND10_SOCKCREATOR_CRASHED)
+                    self.sockcreator = None
+                    self.runnable = False
+            elif pid in self.processes:
                 # One of the processes we know about.  Get information on it.
                 # One of the processes we know about.  Get information on it.
                 proc_info = self.processes.pop(pid)
                 proc_info = self.processes.pop(pid)
                 proc_info.restart_schedule.set_run_stop_time()
                 proc_info.restart_schedule.set_run_stop_time()

+ 31 - 0
src/bin/bind10/sockcreator.py

@@ -16,6 +16,7 @@
 import socket
 import socket
 import struct
 import struct
 import os
 import os
+import subprocess
 from bind10_messages import *
 from bind10_messages import *
 from libutil_io_python import recv_fd
 from libutil_io_python import recv_fd
 
 
@@ -191,3 +192,33 @@ class WrappedSocket:
         Read the file descriptor from the socket.
         Read the file descriptor from the socket.
         """
         """
         return recv_fd(self.fileno())
         return recv_fd(self.fileno())
+
+# FIXME: Any idea how to test this? Starting an external process doesn't sound
+# OK
+class Creator(Parser):
+    """
+    This starts the socket creator and allows asking for the sockets.
+    """
+    def __init__(self, path):
+        (local, remote) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
+        # Popen does not like, for some reason, having the same socket for
+        # stdin as well as stdout, so we dup it before passing it there.
+        remote2 = socket.fromfd(remote.fileno(), socket.AF_UNIX,
+                                socket.SOCK_STREAM)
+        env = os.environ
+        env['PATH'] = path
+        self.__process = subprocess.Popen(['b10-sockcreator'], env=env,
+                                          stdin=remote.fileno(),
+                                          stdout=remote2.fileno())
+        remote.close()
+        remote2.close()
+        Parser.__init__(self, WrappedSocket(local))
+
+    def pid(self):
+        return self.__process.pid
+
+    def kill(self):
+        logger.warn(BIND10_SOCKCREATOR_KILL)
+        if self.__process is not None:
+            self.__process.kill()
+            self.__process = None

+ 8 - 0
src/bin/bind10/tests/bind10_test.py.in

@@ -193,6 +193,13 @@ class MockBob(BoB):
         self.cmdctl = False
         self.cmdctl = False
         self.c_channel_env = {}
         self.c_channel_env = {}
         self.processes = { }
         self.processes = { }
+        self.creator = False
+
+    def start_creator(self):
+        self.creator = True
+
+    def stop_creator(self, kill=False):
+        self.creator = False
 
 
     def read_bind10_config(self):
     def read_bind10_config(self):
         # Configuration options are set directly
         # Configuration options are set directly
@@ -337,6 +344,7 @@ class TestStartStopProcessesBob(unittest.TestCase):
         self.assertEqual(bob.msgq, core)
         self.assertEqual(bob.msgq, core)
         self.assertEqual(bob.cfgmgr, core)
         self.assertEqual(bob.cfgmgr, core)
         self.assertEqual(bob.ccsession, core)
         self.assertEqual(bob.ccsession, core)
+        self.assertEqual(bob.creator, core)
         self.assertEqual(bob.auth, auth)
         self.assertEqual(bob.auth, auth)
         self.assertEqual(bob.resolver, resolver)
         self.assertEqual(bob.resolver, resolver)
         self.assertEqual(bob.xfrout, auth)
         self.assertEqual(bob.xfrout, auth)