BIND 10 trac213, updated. e8e7e9bd02c509454760eb25542e45d8e8374276 Mess checkpoint 3

BIND 10 source code commits bind10-changes at lists.isc.org
Wed Oct 12 14:49:22 UTC 2011


The branch, trac213 has been updated
       via  e8e7e9bd02c509454760eb25542e45d8e8374276 (commit)
       via  9945b1d13a165e1bbfed513040cc0c7536ca6099 (commit)
       via  0e00158cef2a24bcbcab0f70ffd8c3938b67e61d (commit)
      from  a730ddd17c2a20dc55247b5a86d05e3d0bb740fd (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit e8e7e9bd02c509454760eb25542e45d8e8374276
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Wed Oct 12 16:15:25 2011 +0200

    Mess checkpoint 3
    
    * Many more component types are implemented
    * Boss has been stripped of the hardcoded starts
    * There are problems with shutdown
    * No configuration right now, the boss start almost nothing
    * Maybe it will work in the end?
    * Tests completely ignored for now, a lot of them will have to go too.

commit 9945b1d13a165e1bbfed513040cc0c7536ca6099
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Wed Oct 12 14:43:55 2011 +0200

    Mess checkpoint 2
    
    * Boss can register a component and tell it it failed. This version is
      temporary, as it checks for the type, it can be the old ProcessInfo as
      well. Will change, then it should be replaced.
    * Don't raise when shutting down the configurator and something is not
      running. It can happen.

commit 0e00158cef2a24bcbcab0f70ffd8c3938b67e61d
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Wed Oct 12 14:18:09 2011 +0200

    Mess checkpoint 1 - rebase -i and split
    
    * Fix in Makefile
    * Fix in missing process name ‒ default to name
    * Make sockcreator started the new way
    * No tests, no mental capacity to think about them during the boss
      operation, I'm glad it holds together. The boss itself doesn't seem
      much testable anyway.

-----------------------------------------------------------------------

Summary of changes:
 src/bin/bind10/bind10_src.py.in                   |  243 ++++----------------
 src/bin/bind10/tests/bind10_test.py.in            |   19 +-
 src/lib/python/Makefile.am                        |    9 +-
 src/lib/python/bind10_config.py.in                |    4 +
 src/lib/python/isc/bind10/component.py            |   97 ++++++++-
 src/lib/python/isc/bind10/tests/component_test.py |    4 +-
 6 files changed, 153 insertions(+), 223 deletions(-)

-----------------------------------------------------------------------
diff --git a/src/bin/bind10/bind10_src.py.in b/src/bin/bind10/bind10_src.py.in
index 28af8cc..d09ad5b 100755
--- a/src/bin/bind10/bind10_src.py.in
+++ b/src/bin/bind10/bind10_src.py.in
@@ -68,6 +68,7 @@ import isc.net.parse
 import isc.log
 from isc.log_messages.bind10_messages import *
 import isc.bind10.sockcreator
+import isc.bind10.component
 
 isc.log.init("b10-boss")
 logger = isc.log.Logger("boss")
@@ -229,18 +230,11 @@ class BoB:
         """
         self.cc_session = None
         self.ccs = None
-        self.cfg_start_auth = True
-        self.cfg_start_resolver = False
-        self.cfg_start_dhcp6 = False
-        self.cfg_start_dhcp4 = False
-        self.started_auth_family = False
-        self.started_resolver_family = False
         self.curproc = None
         self.dead_processes = {}
         self.msgq_socket_file = msgq_socket_file
         self.nocache = nocache
         self.processes = {}
-        self.expected_shutdowns = {}
         self.runnable = False
         self.uid = setuid
         self.username = username
@@ -250,56 +244,37 @@ class BoB:
         self.cmdctl_port = cmdctl_port
         self.brittle = brittle
         self.sockcreator = None
+        self.__component_configurator = isc.bind10.component.Configurator(self)
+        self.__core_components = {
+            'sockcreator': {
+                'kind': 'core',
+                'special': 'sockcreator',
+                'priority': 200
+            },
+            'msgq': {
+                'kind': 'core',
+                'special': 'msgq',
+                'priority': 199
+            },
+            'cfgmgr': {
+                'kind': 'core',
+                'special': 'cfgmgr',
+                'priority': 198
+            }
+        }
 
     def config_handler(self, new_config):
         # If this is initial update, don't do anything now, leave it to startup
         if not self.runnable:
             return
-        # Now we declare few functions used only internally here. Besides the
-        # benefit of not polluting the name space, they are closures, so we
-        # don't need to pass some variables
-        def start_stop(name, started, start, stop):
-            if not'start_' + name in new_config:
-                return
-            if new_config['start_' + name]:
-                if not started:
-                    if self.uid is not None:
-                        logger.info(BIND10_START_AS_NON_ROOT, name)
-                    start()
-            else:
-                stop()
-        # These four functions are passed to start_stop (smells like functional
-        # programming little bit)
-        def resolver_on():
-            self.start_resolver(self.c_channel_env)
-            self.started_resolver_family = True
-        def resolver_off():
-            self.stop_resolver()
-            self.started_resolver_family = False
-        def auth_on():
-            self.start_auth(self.c_channel_env)
-            self.start_xfrout(self.c_channel_env)
-            self.start_xfrin(self.c_channel_env)
-            self.start_zonemgr(self.c_channel_env)
-            self.started_auth_family = True
-        def auth_off():
-            self.stop_zonemgr()
-            self.stop_xfrin()
-            self.stop_xfrout()
-            self.stop_auth()
-            self.started_auth_family = False
-
-        # The real code of the config handler function follows here
         logger.debug(DBG_COMMANDS, BIND10_RECEIVED_NEW_CONFIGURATION,
                      new_config)
-        start_stop('resolver', self.started_resolver_family, resolver_on,
-            resolver_off)
-        start_stop('auth', self.started_auth_family, auth_on, auth_off)
-
+        # TODO: Propagate the config to the configurator
         answer = isc.config.ccsession.create_answer(0)
         return answer
 
     def get_processes(self):
+        # FIXME: This is all wrong.
         pids = list(self.processes.keys())
         pids.sort()
         process_list = [ ]
@@ -349,15 +324,6 @@ class BoB:
         self.sockcreator = isc.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):
         """
             Called as part of the exception handling when a process fails to
@@ -372,6 +338,8 @@ class BoB:
             logger.info(BIND10_KILL_PROCESS, self.processes[pid].name)
             self.processes[pid].process.kill()
         self.processes = {}
+        if self.__component_configurator.running():
+            self.__component_configurator.shutdown()
 
     def read_bind10_config(self):
         """
@@ -386,11 +354,7 @@ class BoB:
         logger.info(BIND10_READING_BOSS_CONFIGURATION)
 
         config_data = self.ccs.get_full_config()
-        self.cfg_start_auth = config_data.get("start_auth")
-        self.cfg_start_resolver = config_data.get("start_resolver")
-
-        logger.info(BIND10_CONFIGURATION_START_AUTH, self.cfg_start_auth)
-        logger.info(BIND10_CONFIGURATION_START_RESOLVER, self.cfg_start_resolver)
+        # Propagate the config to the config manager, first reconfigure
 
     def log_starting(self, process, port = None, address = None):
         """
@@ -431,16 +395,15 @@ class BoB:
     # raised which is caught by the caller of start_all_processes(); this kills
     # processes started up to that point before terminating the program.
 
-    def start_msgq(self, c_channel_env):
+    def start_msgq(self):
         """
             Start the message queue and connect to the command channel.
         """
         self.log_starting("b10-msgq")
-        c_channel = ProcessInfo("b10-msgq", ["b10-msgq"], c_channel_env,
+        c_channel = ProcessInfo("b10-msgq", ["b10-msgq"], self.c_channel_env,
                                 True, not self.verbose, uid=self.uid,
                                 username=self.username)
         c_channel.spawn()
-        self.processes[c_channel.pid] = c_channel
         self.log_started(c_channel.pid)
 
         # Now connect to the c-channel
@@ -450,13 +413,14 @@ class BoB:
             if (time.time() - cc_connect_start) > 5:
                 raise CChannelConnectError("Unable to connect to c-channel after 5 seconds")
 
-            # try to connect, and if we can't wait a short while
+            # try to connect, and if we can't, wait a short while
             try:
                 self.cc_session = isc.cc.Session(self.msgq_socket_file)
             except isc.cc.session.SessionError:
                 time.sleep(0.1)
+        return c_channel
 
-    def start_cfgmgr(self, c_channel_env):
+    def start_cfgmgr(self):
         """
             Starts the configuration manager process
         """
@@ -467,10 +431,9 @@ class BoB:
         if self.config_filename is not None:
             args.append("--config-filename=" + self.config_filename)
         bind_cfgd = ProcessInfo("b10-cfgmgr", args,
-                                c_channel_env, uid=self.uid,
+                                self.c_channel_env, uid=self.uid,
                                 username=self.username)
         bind_cfgd.spawn()
-        self.processes[bind_cfgd.pid] = bind_cfgd
         self.log_started(bind_cfgd.pid)
 
         # sleep until b10-cfgmgr is fully up and running, this is a good place
@@ -478,6 +441,7 @@ class BoB:
         # TODO: replace the sleep by a listen for ConfigManager started
         # message
         time.sleep(1)
+        return bind_cfgd
 
     def start_ccsession(self, c_channel_env):
         """
@@ -509,7 +473,7 @@ class BoB:
         self.processes[newproc.pid] = newproc
         self.log_started(newproc.pid)
 
-    def start_simple(self, name, c_channel_env, port=None, address=None):
+    def start_simple(self, name):
         """
             Most of the BIND-10 processes are started with the command:
 
@@ -526,7 +490,7 @@ class BoB:
             args += ['-v']
 
         # ... and start the process
-        self.start_process(name, args, c_channel_env, port, address)
+        self.start_process(name, args, self.c_channel_env)
 
     # The next few methods start up the rest of the BIND-10 processes.
     # Although many of these methods are little more than a call to
@@ -566,24 +530,6 @@ class BoB:
         # ... and start
         self.start_process("b10-resolver", resargs, c_channel_env)
 
-    def start_xfrout(self, c_channel_env):
-        self.start_simple("b10-xfrout", c_channel_env)
-
-    def start_xfrin(self, c_channel_env):
-        self.start_simple("b10-xfrin", c_channel_env)
-
-    def start_zonemgr(self, c_channel_env):
-        self.start_simple("b10-zonemgr", c_channel_env)
-
-    def start_stats(self, c_channel_env):
-        self.start_simple("b10-stats", c_channel_env)
-
-    def start_stats_httpd(self, c_channel_env):
-        self.start_simple("b10-stats-httpd", c_channel_env)
-
-    def start_dhcp6(self, c_channel_env):
-        self.start_simple("b10-dhcp6", c_channel_env)
-
     def start_cmdctl(self, c_channel_env):
         """
             Starts the command control process
@@ -598,52 +544,17 @@ class BoB:
             Starts up all the processes.  Any exception generated during the
             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()
+        self.__component_configurator.startup(self.__core_components)
         # TODO: Once everything uses the socket creator, we can drop root
         # privileges right now
 
         c_channel_env = self.c_channel_env
-        self.start_msgq(c_channel_env)
-        self.start_cfgmgr(c_channel_env)
         self.start_ccsession(c_channel_env)
 
         # Extract the parameters associated with Bob.  This can only be
         # done after the CC Session is started.
         self.read_bind10_config()
 
-        # Continue starting the processes.  The authoritative server (if
-        # selected):
-        if self.cfg_start_auth:
-            self.start_auth(c_channel_env)
-
-        # ... and resolver (if selected):
-        if self.cfg_start_resolver:
-            self.start_resolver(c_channel_env)
-            self.started_resolver_family = True
-
-        # Everything after the main components can run as non-root.
-        # TODO: this is only temporary - once the privileged socket creator is
-        # fully working, nothing else will run as root.
-        if self.uid is not None:
-            posix.setuid(self.uid)
-
-        # xfrin/xfrout and the zone manager are only meaningful if the
-        # authoritative server has been started.
-        if self.cfg_start_auth:
-            self.start_xfrout(c_channel_env)
-            self.start_xfrin(c_channel_env)
-            self.start_zonemgr(c_channel_env)
-            self.started_auth_family = True
-
-        # ... and finally start the remaining processes
-        self.start_stats(c_channel_env)
-        self.start_stats_httpd(c_channel_env)
-        self.start_cmdctl(c_channel_env)
-
-        if self.cfg_start_dhcp6:
-            self.start_dhcp6(c_channel_env)
-
     def startup(self):
         """
             Start the BoB instance.
@@ -683,17 +594,7 @@ class BoB:
         """Stop all processes."""
         cmd = { "command": ['shutdown']}
 
-        self.cc_session.group_sendmsg(cmd, 'Cmdctl', 'Cmdctl')
-        self.cc_session.group_sendmsg(cmd, "ConfigManager", "ConfigManager")
-        self.cc_session.group_sendmsg(cmd, "Auth", "Auth")
-        self.cc_session.group_sendmsg(cmd, "Resolver", "Resolver")
-        self.cc_session.group_sendmsg(cmd, "Xfrout", "Xfrout")
-        self.cc_session.group_sendmsg(cmd, "Xfrin", "Xfrin")
-        self.cc_session.group_sendmsg(cmd, "Zonemgr", "Zonemgr")
-        self.cc_session.group_sendmsg(cmd, "Stats", "Stats")
-        self.cc_session.group_sendmsg(cmd, "StatsHttpd", "StatsHttpd")
-        # Terminate the creator last
-        self.stop_creator()
+        self.__component_configurator.shutdown()
 
     def stop_process(self, process, recipient):
         """
@@ -701,31 +602,14 @@ class BoB:
         (in logs, etc), the recipient is the address on msgq.
         """
         logger.info(BIND10_STOP_PROCESS, process)
-        # TODO: Some timeout to solve processes that don't want to die would
-        # help. We can even store it in the dict, it is used only as a set
-        self.expected_shutdowns[process] = 1
         # Ask the process to die willingly
         self.cc_session.group_sendmsg({'command': ['shutdown']}, recipient,
             recipient)
 
-    # Series of stop_process wrappers
-    def stop_resolver(self):
-        self.stop_process('b10-resolver', 'Resolver')
-
-    def stop_auth(self):
-        self.stop_process('b10-auth', 'Auth')
-
-    def stop_xfrout(self):
-        self.stop_process('b10-xfrout', 'Xfrout')
-
-    def stop_xfrin(self):
-        self.stop_process('b10-xfrin', 'Xfrin')
-
-    def stop_zonemgr(self):
-        self.stop_process('b10-zonemgr', 'Zonemgr')
-
-    def shutdown(self):
+    def shutdown(self, exitcode=0):
         """Stop the BoB instance."""
+        # FIXME: This is called from various places.
+        # Do something about it, as each shutdown is different one
         logger.info(BIND10_SHUTDOWN)
         # first try using the BIND 10 request to stop
         try:
@@ -733,9 +617,9 @@ class BoB:
         except:
             pass
         # XXX: some delay probably useful... how much is uncertain
-        # I have changed the delay from 0.5 to 1, but sometime it's 
+        # I have changed the delay from 0.5 to 1, but sometime it's
         # still not enough.
-        time.sleep(1)  
+        time.sleep(1)
         self.reap_children()
         # next try sending a SIGTERM
         processes_to_stop = list(self.processes.values())
@@ -743,6 +627,7 @@ class BoB:
             logger.info(BIND10_SEND_SIGTERM, proc_info.name,
                         proc_info.pid)
             try:
+                # FIXME: This won't work. We replaced them with something else
                 proc_info.process.terminate()
             except OSError:
                 # ignore these (usually ESRCH because the child
@@ -751,7 +636,7 @@ class BoB:
         # finally, send SIGKILL (unmaskable termination) until everybody dies
         while self.processes:
             # XXX: some delay probably useful... how much is uncertain
-            time.sleep(0.1)  
+            time.sleep(0.1)
             self.reap_children()
             processes_to_stop = list(self.processes.values())
             for proc_info in processes_to_stop:
@@ -780,40 +665,11 @@ class BoB:
                 # XXX: should be impossible to get any other error here
                 raise
             if pid == 0: break
-            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:
+            if pid in self.processes:
                 # One of the processes we know about.  Get information on it.
-                proc_info = self.processes.pop(pid)
-                proc_info.restart_schedule.set_run_stop_time()
-                self.dead_processes[proc_info.pid] = proc_info
-
-                # Write out message, but only if in the running state:
-                # During startup and shutdown, these messages are handled
-                # elsewhere.
-                if self.runnable:
-                    if exit_status is None:
-                        logger.warn(BIND10_PROCESS_ENDED_NO_EXIT_STATUS,
-                                    proc_info.name, proc_info.pid)
-                    else:
-                        logger.warn(BIND10_PROCESS_ENDED_WITH_EXIT_STATUS,
-                                    proc_info.name, proc_info.pid,
-                                    exit_status)
-
-                    # Was it a special process?
-                    if proc_info.name == "b10-msgq":
-                        logger.fatal(BIND10_MSGQ_DAEMON_ENDED)
-                        self.runnable = False
-
-                # If we're in 'brittle' mode, we want to shutdown after
-                # any process dies.
-                if self.brittle:
-                    self.runnable = False
+                component = self.processes.pop(pid)
+                if component.running():
+                    component.failed()
             else:
                 logger.info(BIND10_UNKNOWN_CHILD_PROCESS_ENDED, pid)
 
@@ -836,10 +692,6 @@ class BoB:
         still_dead = {}
         now = time.time()
         for proc_info in self.dead_processes.values():
-            if proc_info.name in self.expected_shutdowns:
-                # We don't restart, we wanted it to die
-                del self.expected_shutdowns[proc_info.name]
-                continue
             restart_time = proc_info.restart_schedule.get_restart_time(now)
             if restart_time > now:
                 if (next_restart is None) or (next_restart > restart_time):
@@ -858,6 +710,9 @@ class BoB:
         # return the time when the next process is ready to be restarted
         return next_restart
 
+    def register_process(self, pid, info):
+        self.processes[pid] = info
+
 # global variables, needed for signal handlers
 options = None
 boss_of_bind = None
diff --git a/src/bin/bind10/tests/bind10_test.py.in b/src/bin/bind10/tests/bind10_test.py.in
index 424a610..3c9b12e 100644
--- a/src/bin/bind10/tests/bind10_test.py.in
+++ b/src/bin/bind10/tests/bind10_test.py.in
@@ -14,6 +14,7 @@
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 from bind10_src import ProcessInfo, BoB, parse_args, dump_pid, unlink_pid_file, _BASETIME
+from isc.bind10.component import Component
 
 # XXX: environment tests are currently disabled, due to the preprocessor
 #      setup that we have now complicating the environment
@@ -173,6 +174,13 @@ class TestBoB(unittest.TestCase):
         self.assertEqual(bob.command_handler("__UNKNOWN__", None),
                          isc.config.ccsession.create_answer(1, "Unknown command"))
 
+class TestComponent(Component):
+    def start_internal(self):
+        pass
+
+    def stop_internal(self, Kill=False):
+        pass
+
 # Class for testing the BoB without actually starting processes.
 # This is used for testing the start/stop components routines and
 # the BoB commands.
@@ -199,13 +207,7 @@ class MockBob(BoB):
         self.cmdctl = False
         self.c_channel_env = {}
         self.processes = { }
-        self.creator = False
-
-    def start_creator(self):
-        self.creator = True
-
-    def stop_creator(self, kill=False):
-        self.creator = False
+        isc.bind10.component.specials['sockcreator'] = TestComponent
 
     def read_bind10_config(self):
         # Configuration options are set directly
@@ -350,7 +352,6 @@ class TestStartStopProcessesBob(unittest.TestCase):
         self.assertEqual(bob.msgq, core)
         self.assertEqual(bob.cfgmgr, core)
         self.assertEqual(bob.ccsession, core)
-        self.assertEqual(bob.creator, core)
         self.assertEqual(bob.auth, auth)
         self.assertEqual(bob.resolver, resolver)
         self.assertEqual(bob.xfrout, auth)
@@ -590,6 +591,8 @@ class TestStartStopProcessesBob(unittest.TestCase):
         self.check_started_dhcp(bob, False, False)
 
         # v6 only enabled
+        bob = MockBob()
+        self.check_preconditions(bob)
         bob.cfg_start_dhcp6 = True
         bob.cfg_start_dhcp4 = False
         bob.start_all_processes()
diff --git a/src/lib/python/Makefile.am b/src/lib/python/Makefile.am
index 5924294..893bb8c 100644
--- a/src/lib/python/Makefile.am
+++ b/src/lib/python/Makefile.am
@@ -1,15 +1,8 @@
 SUBDIRS = isc
 
-python_PYTHON =	bind10_config.py
+nodist_python_PYTHON =	bind10_config.py
 pythondir = $(pyexecdir)
 
-# Explicitly define DIST_COMMON so ${python_PYTHON} is not included
-# as we don't want the generated file included in distributed tarfile.
-DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in bind10_config.py.in
-
-# When setting DIST_COMMON, then need to add the .in file too.
-EXTRA_DIST =  bind10_config.py.in
-
 CLEANFILES = bind10_config.pyc
 CLEANDIRS = __pycache__
 
diff --git a/src/lib/python/bind10_config.py.in b/src/lib/python/bind10_config.py.in
index 69b17ed..e54b1a8 100644
--- a/src/lib/python/bind10_config.py.in
+++ b/src/lib/python/bind10_config.py.in
@@ -23,6 +23,10 @@ def reload():
     global DATA_PATH
     global PLUGIN_PATHS
     global PREFIX
+    global LIBEXECDIR
+    LIBEXECDIR = ("@libexecdir@/@PACKAGE@"). \
+        replace("${exec_prefix}", "@exec_prefix@"). \
+        replace("${prefix}", "@prefix@")
     BIND10_MSGQ_SOCKET_FILE = os.path.join("@localstatedir@",
                                            "@PACKAGE_NAME@",
                                            "msgq_socket").replace("${prefix}",
diff --git a/src/lib/python/isc/bind10/component.py b/src/lib/python/isc/bind10/component.py
index 6150c7c..208b3d4 100644
--- a/src/lib/python/isc/bind10/component.py
+++ b/src/lib/python/isc/bind10/component.py
@@ -13,8 +13,11 @@
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
+import isc.bind10.sockcreator
 from isc.log_messages.bind10_messages import *
 import time
+from bind10_config import LIBEXECDIR
+import os
 
 logger = isc.log.Logger("boss")
 
@@ -34,7 +37,7 @@ class Component:
     it might be inherited and modified for special-purpose components,
     like the core modules with different ways of starting up.
     """
-    def __init__(self, process, boss, kind):
+    def __init__(self, process, boss, kind, address=None, params=None):
         """
         Creates the component in not running mode.
 
@@ -62,7 +65,11 @@ class Component:
         # Dead like really dead. No resurrection possible.
         self.__dead = False
         self.__kind = kind
-        self.__boss = boss
+        self._boss = boss
+        self._process = process
+        self._start_func = None
+        self._address = address
+        self._params = params
 
     def start(self):
         """
@@ -89,9 +96,15 @@ class Component:
         This method does the actual starting of a process. If you need to
         change the way the component is started, replace this method.
         """
-        pass
+        if self._start_func is not None:
+            procinfo = self._start_func()
+        else:
+            # TODO Handle params, etc
+            procinfo = self._boss.start_simple(self._process)
+        self._procinfo = procinfo
+        self._boss.register_process(procinfo.pid, self)
 
-    def stop(self):
+    def stop(self, kill=False):
         """
         Stop the component. If you need to modify the way a component is
         stopped, do not replace this method, but stop_internal. This one
@@ -102,15 +115,15 @@ class Component:
         """
         if not self.running():
             raise ValueError("Can't stop a component which is not running")
-        self.stop_internal()
+        self.stop_internal(kill)
         self.__running = False
 
-    def stop_internal(self):
+    def stop_internal(self, kill=False):
         """
         This is the method that does the actual stopping of a component.
         You can replace this method if you want a different way to do it.
         """
-        pass
+        self._boss.stop_process(self._process, self._address)
 
     def failed(self):
         """
@@ -128,7 +141,7 @@ class Component:
         if self.__kind == 'core' or \
             (self.__kind == 'needed' and time.time() - 10 < self.__start_time):
             self.__dead = True
-            self.__boss.shutdown(1)
+            self._boss.shutdown(1)
         # This means we want to restart
         else:
             self.start()
@@ -152,7 +165,65 @@ class Component:
         """
         return self.__running
 
-specials = {}
+class SockCreator(Component):
+    def start_internal(self):
+        self._boss.curproc = 'b10-sockcreator'
+        print( LIBEXECDIR)
+        self.__creator = isc.bind10.sockcreator.Creator(LIBEXECDIR + ':' +
+                                                        os.environ['PATH'])
+        self._boss.register_process(self.__creator.pid(), self)
+
+    def stop_internal(self, kill=False):
+        if self.__creator is None:
+            return
+        if kill:
+            self.__creator.kill()
+        else:
+            self.sockcreator.terminate()
+        self.__creator = None
+
+class Msgq(Component):
+    def __init__(self, process, boss, kind):
+        Component.__init__(self, process, boss, kind)
+        self._start_func = boss.start_msgq
+
+    def stop_internal(self):
+        pass # Wait for the boss to actually kill it. There's no stop command.
+
+class CfgMgr(Component):
+    def __init__(self, process, boss, kind):
+        Component.__init__(self, process, boss, kind)
+        self._start_func = boss.start_cfgmgr
+        self._address = 'ConfigManager'
+
+class Auth(Component):
+    def __init__(self, process, boss, kind):
+        Component.__init__(self, process, boss, kind)
+        self._start_func = boss.start_auth
+        self._address = 'Auth'
+
+class Resolver(Component):
+    def __init__(self, process, boss, kind):
+        Component.__init__(self, process, boss, kind)
+        self._start_func = boss.start_resolver
+        self._address = 'Resolver'
+
+class CmdCtl(Component):
+    def __init__(self, process, boss, kind):
+        Component.__init__(self, process, boss, kind)
+        self._start_func = boss.start_cmdctl
+        self._address = 'Cmdctl'
+
+specials = {
+    'sockcreator': SockCreator,
+    'msgq': Msgq,
+    'cfgmgr': CfgMgr,
+    # TODO: Should these be replaced by configuration in config manager only?
+    # They should not have any parameters anyway
+    'auth': Auth,
+    'resolver': Resolver,
+    'cmdctl': CmdCtl
+}
 """
 List of specially started components. Each one should be the class than can
 be created for that component.
@@ -262,7 +333,7 @@ class Configurator:
                 if 'special' in params:
                     # TODO: Better error handling
                     creator = specials[params['special']]
-                component = creator(params['process'], self.__boss,
+                component = creator(params.get('process', cname), self.__boss,
                                     params['kind'])
                 priority = params.get('priority', 0)
                 # We store tuples, priority first, so we can easily sort
@@ -276,6 +347,9 @@ class Configurator:
                                                         reverse=True)])
         return plan
 
+    def running(self):
+        return self._running
+
     def _run_plan(self, plan):
         """
         Run a plan, created beforehead by _build_plan.
@@ -294,7 +368,8 @@ class Configurator:
                 component.start()
                 self._components[task['name']] = component
             elif command == 'stop':
-                component.stop()
+                if component.running():
+                    component.stop()
                 del self._components[task['name']]
             else:
                 # Can Not Happen (as the plans are generated by ourself).
diff --git a/src/lib/python/isc/bind10/tests/component_test.py b/src/lib/python/isc/bind10/tests/component_test.py
index 5133039..bb96937 100644
--- a/src/lib/python/isc/bind10/tests/component_test.py
+++ b/src/lib/python/isc/bind10/tests/component_test.py
@@ -89,7 +89,7 @@ class ComponentTests(BossUtils, unittest.TestCase):
         """
         self.__start_called = True
 
-    def __stop(self):
+    def __stop(self, kill=False):
         """
         Mock function, installed into the component into stop_internal.
         This only notes the component was "stopped".
@@ -396,7 +396,7 @@ class TestComponent(Component):
     def start_internal(self):
         self.log('start')
 
-    def stop_internal(self):
+    def stop_internal(self, kill=False):
         self.log('stop')
 
     def failed_internal(self):




More information about the bind10-changes mailing list