Browse Source

[213-incremental] use the new component/configurator frameork only for start/stop. no spec file change, no restart with the framework.

JINMEI Tatuya 13 years ago
parent
commit
3f070803d6
2 changed files with 252 additions and 166 deletions
  1. 149 116
      src/bin/bind10/bind10_src.py.in
  2. 103 50
      src/bin/bind10/tests/bind10_test.py.in

+ 149 - 116
src/bin/bind10/bind10_src.py.in

@@ -70,7 +70,8 @@ import isc.util.process
 import isc.net.parse
 import isc.net.parse
 import isc.log
 import isc.log
 from isc.log_messages.bind10_messages import *
 from isc.log_messages.bind10_messages import *
-import isc.bind10.sockcreator
+import isc.bind10.component
+import isc.bind10.special_component
 
 
 isc.log.init("b10-boss")
 isc.log.init("b10-boss")
 logger = isc.log.Logger("boss")
 logger = isc.log.Logger("boss")
@@ -251,6 +252,7 @@ class BoB:
         self.dead_processes = {}
         self.dead_processes = {}
         self.msgq_socket_file = msgq_socket_file
         self.msgq_socket_file = msgq_socket_file
         self.nocache = nocache
         self.nocache = nocache
+        self.component_config = {}
         self.processes = {}
         self.processes = {}
         self.expected_shutdowns = {}
         self.expected_shutdowns = {}
         self.runnable = False
         self.runnable = False
@@ -263,11 +265,47 @@ class BoB:
         self.brittle = brittle
         self.brittle = brittle
         self.wait_time = wait_time
         self.wait_time = wait_time
         self.sockcreator = None
         self.sockcreator = None
+        self._component_configurator = isc.bind10.component.Configurator(self,
+            isc.bind10.special_component.get_specials())
+        # The priorities here make them start in the correct order. First
+        # the socket creator (which would drop root privileges by then),
+        # then message queue and after that the config manager (which uses
+        # the config manager)
+        self.__core_components = {
+            'sockcreator': {
+                'kind': 'core',
+                'special': 'sockcreator',
+                'priority': 200
+            },
+            'msgq': {
+                'kind': 'core',
+                'special': 'msgq',
+                'priority': 199
+            },
+            'cfgmgr': {
+                'kind': 'core',
+                'special': 'cfgmgr',
+                'priority': 198
+            }
+        }
+        self.__started = False
+        self.exitcode = 0
 
 
         # If -v was set, enable full debug logging.
         # If -v was set, enable full debug logging.
         if self.verbose:
         if self.verbose:
             logger.set_severity("DEBUG", 99)
             logger.set_severity("DEBUG", 99)
 
 
+    def __propagate_component_config(self, config):
+        comps = dict(config)
+        # Fill in the core components, so they stay alive
+        for comp in self.__core_components:
+            if comp in comps:
+                raise Exception(comp + " is core component managed by " +
+                                "bind10 boss, do not set it")
+            comps[comp] = self.__core_components[comp]
+        # Update the configuration
+        self._component_configurator.reconfigure(comps)
+
     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
         if not self.runnable:
         if not self.runnable:
@@ -288,29 +326,43 @@ class BoB:
         # These four functions are passed to start_stop (smells like functional
         # These four functions are passed to start_stop (smells like functional
         # programming little bit)
         # programming little bit)
         def resolver_on():
         def resolver_on():
-            self.start_resolver(self.c_channel_env)
+            self.component_config['b10-resolver'] = { 'kind': 'needed',
+                                                      'special': 'resolver' }
+            self.__propagate_component_config(self.component_config)
             self.started_resolver_family = True
             self.started_resolver_family = True
         def resolver_off():
         def resolver_off():
-            self.stop_resolver()
+            if 'b10-resolver' in self.component_config:
+                del self.component_config['b10-resolver']
+            self.__propagate_component_config(self.component_config)
             self.started_resolver_family = False
             self.started_resolver_family = False
         def auth_on():
         def auth_on():
-            self.start_auth(self.c_channel_env)
+            self.component_config['b10-auth'] = { 'kind': 'needed',
-            self.start_xfrout(self.c_channel_env)
+                                                  'special': 'auth' }
-            self.start_xfrin(self.c_channel_env)
+            self.component_config['b10-xfrout'] = { 'kind': 'dispensable',
-            self.start_zonemgr(self.c_channel_env)
+                                                    'address': 'Xfrout' }
+            self.component_config['b10-xfrin'] = { 'kind': 'dispensable',
+                                                   'address': 'Xfrin' }
+            self.component_config['b10-zonemgr'] = { 'kind': 'dispensable',
+                                                     'address': 'Zonemgr' }
+            self.__propagate_component_config(self.component_config)
             self.started_auth_family = True
             self.started_auth_family = True
         def auth_off():
         def auth_off():
-            self.stop_zonemgr()
+            if 'b10-zonemgr' in self.component_config:
-            self.stop_xfrin()
+                del self.component_config['b10-zonemgr']
-            self.stop_xfrout()
+            if 'b10-xfrin' in self.component_config:
-            self.stop_auth()
+                del self.component_config['b10-xfrin']
+            if 'b10-xfrout' in self.component_config:
+                del self.component_config['b10-xfrout']
+            if 'b10-auth' in self.component_config:
+                del self.component_config['b10-auth']
+            self.__propagate_component_config(self.component_config)
             self.started_auth_family = False
             self.started_auth_family = False
 
 
         # The real code of the config handler function follows here
         # The real code of the config handler function follows here
         logger.debug(DBG_COMMANDS, BIND10_RECEIVED_NEW_CONFIGURATION,
         logger.debug(DBG_COMMANDS, BIND10_RECEIVED_NEW_CONFIGURATION,
                      new_config)
                      new_config)
         start_stop('resolver', self.started_resolver_family, resolver_on,
         start_stop('resolver', self.started_resolver_family, resolver_on,
-            resolver_off)
+                   resolver_off)
         start_stop('auth', self.started_auth_family, auth_on, auth_off)
         start_stop('auth', self.started_auth_family, auth_on, auth_off)
 
 
         answer = isc.config.ccsession.create_answer(0)
         answer = isc.config.ccsession.create_answer(0)
@@ -370,22 +422,6 @@ class BoB:
                                                             "Unknown command")
                                                             "Unknown command")
         return answer
         return answer
 
 
-    def start_creator(self):
-        self.curproc = 'b10-sockcreator'
-        creator_path = os.environ['PATH']
-        if ADD_LIBEXEC_PATH:
-            creator_path = "@@LIBEXECDIR@@:" + creator_path
-        self.sockcreator = isc.bind10.sockcreator.Creator(creator_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
@@ -480,17 +516,16 @@ class BoB:
     # raised which is caught by the caller of start_all_processes(); this kills
     # raised which is caught by the caller of start_all_processes(); this kills
     # processes started up to that point before terminating the program.
     # 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.
             Start the message queue and connect to the command channel.
         """
         """
         self.log_starting("b10-msgq")
         self.log_starting("b10-msgq")
-        c_channel = ProcessInfo("b10-msgq", ["b10-msgq"], c_channel_env,
+        msgq_proc = ProcessInfo("b10-msgq", ["b10-msgq"], self.c_channel_env,
                                 True, not self.verbose, uid=self.uid,
                                 True, not self.verbose, uid=self.uid,
                                 username=self.username)
                                 username=self.username)
-        c_channel.spawn()
+        msgq_proc.spawn()
-        self.processes[c_channel.pid] = c_channel
+        self.log_started(msgq_proc.pid)
-        self.log_started(c_channel.pid)
 
 
         # Now connect to the c-channel
         # Now connect to the c-channel
         cc_connect_start = time.time()
         cc_connect_start = time.time()
@@ -509,7 +544,9 @@ class BoB:
         # on this channel are once relating to process startup.
         # on this channel are once relating to process startup.
         self.cc_session.group_subscribe("Boss")
         self.cc_session.group_subscribe("Boss")
 
 
-    def start_cfgmgr(self, c_channel_env):
+        return msgq_proc
+
+    def start_cfgmgr(self):
         """
         """
             Starts the configuration manager process
             Starts the configuration manager process
         """
         """
@@ -520,10 +557,9 @@ class BoB:
         if self.config_filename is not None:
         if self.config_filename is not None:
             args.append("--config-filename=" + self.config_filename)
             args.append("--config-filename=" + self.config_filename)
         bind_cfgd = ProcessInfo("b10-cfgmgr", args,
         bind_cfgd = ProcessInfo("b10-cfgmgr", args,
-                                c_channel_env, uid=self.uid,
+                                self.c_channel_env, uid=self.uid,
                                 username=self.username)
                                 username=self.username)
         bind_cfgd.spawn()
         bind_cfgd.spawn()
-        self.processes[bind_cfgd.pid] = bind_cfgd
         self.log_started(bind_cfgd.pid)
         self.log_started(bind_cfgd.pid)
 
 
         # Wait for the configuration manager to start up as subsequent initialization
         # Wait for the configuration manager to start up as subsequent initialization
@@ -539,6 +575,8 @@ class BoB:
         if not self.process_running(msg, "ConfigManager"):
         if not self.process_running(msg, "ConfigManager"):
             raise ProcessStartError("Configuration manager process has not started")
             raise ProcessStartError("Configuration manager process has not started")
 
 
+        return bind_cfgd
+
     def start_ccsession(self, c_channel_env):
     def start_ccsession(self, c_channel_env):
         """
         """
             Start the CC Session
             Start the CC Session
@@ -570,10 +608,22 @@ class BoB:
         self.log_starting(name, port, address)
         self.log_starting(name, port, address)
         newproc = ProcessInfo(name, args, c_channel_env)
         newproc = ProcessInfo(name, args, c_channel_env)
         newproc.spawn()
         newproc.spawn()
-        self.processes[newproc.pid] = newproc
+        # This is now done in register_process()
+        #self.processes[newproc.pid] = newproc
         self.log_started(newproc.pid)
         self.log_started(newproc.pid)
+        return newproc
 
 
-    def start_simple(self, name, c_channel_env, port=None, address=None):
+    def register_process(self, pid, info):
+        """
+        Put another process into boss to watch over it.  When the process
+        dies, the info.failed() is called with the exit code.
+        """
+        self.processes[pid] = info._procinfo
+        if info._procinfo is None:
+            # XXX: a short term hack.  This is the sockcreator.
+            self.sockcreator = info._SockCreator__creator
+
+    def start_simple(self, name):
         """
         """
             Most of the BIND-10 processes are started with the command:
             Most of the BIND-10 processes are started with the command:
 
 
@@ -590,7 +640,7 @@ class BoB:
             args += ['-v']
             args += ['-v']
 
 
         # ... and start the process
         # ... and start the process
-        self.start_process(name, args, c_channel_env, port, address)
+        return self.start_process(name, args, self.c_channel_env)
 
 
     # The next few methods start up the rest of the BIND-10 processes.
     # 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
     # Although many of these methods are little more than a call to
@@ -598,7 +648,7 @@ class BoB:
     # where modifications can be made if the process start-up sequence changes
     # where modifications can be made if the process start-up sequence changes
     # for a given process.
     # for a given process.
 
 
-    def start_auth(self, c_channel_env):
+    def start_auth(self):
         """
         """
             Start the Authoritative server
             Start the Authoritative server
         """
         """
@@ -611,9 +661,9 @@ class BoB:
             authargs += ['-v']
             authargs += ['-v']
 
 
         # ... and start
         # ... and start
-        self.start_process("b10-auth", authargs, c_channel_env)
+        return self.start_process("b10-auth", authargs, self.c_channel_env)
 
 
-    def start_resolver(self, c_channel_env):
+    def start_resolver(self):
         """
         """
             Start the Resolver.  At present, all these arguments and switches
             Start the Resolver.  At present, all these arguments and switches
             are pure speculation.  As with the auth daemon, they should be
             are pure speculation.  As with the auth daemon, they should be
@@ -628,68 +678,29 @@ class BoB:
             resargs += ['-v']
             resargs += ['-v']
 
 
         # ... and start
         # ... and start
-        self.start_process("b10-resolver", resargs, c_channel_env)
+        return self.start_process("b10-resolver", resargs, self.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):
-        # XXX: a quick-hack workaround.  xfrin will implicitly use dynamically
-        # loadable data source modules, which will be installed in $(libdir).
-        # On some OSes (including MacOS X and *BSDs) the main process (python)
-        # cannot find the modules unless they are located in a common shared
-        # object path or a path in the (DY)LD_LIBRARY_PATH.  We should seek
-        # a cleaner solution, but for a short term workaround we specify the
-        # path here, unconditionally, and without even bothering which
-        # environment variable should be used.
-        #
-        # We reuse the ADD_LIBEXEC_PATH variable to see whether we need to
-        # do this, as the conditions that make this workaround needed are
-        # the same as for the libexec path addition
-        if ADD_LIBEXEC_PATH:
-            cur_path = os.getenv('DYLD_LIBRARY_PATH')
-            cur_path = '' if cur_path is None else ':' + cur_path
-            c_channel_env['DYLD_LIBRARY_PATH'] = "@@LIBDIR@@" + cur_path
-
-            cur_path = os.getenv('LD_LIBRARY_PATH')
-            cur_path = '' if cur_path is None else ':' + cur_path
-            c_channel_env['LD_LIBRARY_PATH'] = "@@LIBDIR@@" + cur_path
-        self.start_simple("b10-xfrin", c_channel_env)
 
 
-    def start_zonemgr(self, c_channel_env):
+    def start_cmdctl(self):
-        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
             Starts the command control process
         """
         """
         args = ["b10-cmdctl"]
         args = ["b10-cmdctl"]
         if self.cmdctl_port is not None:
         if self.cmdctl_port is not None:
             args.append("--port=" + str(self.cmdctl_port))
             args.append("--port=" + str(self.cmdctl_port))
-        self.start_process("b10-cmdctl", args, c_channel_env, self.cmdctl_port)
+        return self.start_process("b10-cmdctl", args, self.c_channel_env,
+                                  self.cmdctl_port)
 
 
     def start_all_processes(self):
     def start_all_processes(self):
         """
         """
             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
+        # Start the real core (sockcreator, msgq, cfgmgr)
-        self.start_creator()
+        self._component_configurator.startup(self.__core_components)
-        # TODO: Once everything uses the socket creator, we can drop root
-        # privileges right now
 
 
+        # Connect to the msgq. This is not a process, so it's not handled
+        # inside the configurator.
         c_channel_env = self.c_channel_env
         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)
         self.start_ccsession(c_channel_env)
 
 
         # Extract the parameters associated with Bob.  This can only be
         # Extract the parameters associated with Bob.  This can only be
@@ -699,12 +710,16 @@ class BoB:
 
 
         # Continue starting the processes.  The authoritative server (if
         # Continue starting the processes.  The authoritative server (if
         # selected):
         # selected):
+        component_config = {}
         if self.cfg_start_auth:
         if self.cfg_start_auth:
-            self.start_auth(c_channel_env)
+            component_config['b10-auth'] = { 'kind': 'needed',
+                                             'special': 'auth' }
+            self.__propagate_component_config(component_config)
 
 
         # ... and resolver (if selected):
         # ... and resolver (if selected):
         if self.cfg_start_resolver:
         if self.cfg_start_resolver:
-            self.start_resolver(c_channel_env)
+            component_config['b10-resolver'] = { 'kind': 'needed',
+                                                 'special': 'resolver' }
             self.started_resolver_family = True
             self.started_resolver_family = True
 
 
         # Everything after the main components can run as non-root.
         # Everything after the main components can run as non-root.
@@ -716,18 +731,30 @@ class BoB:
         # xfrin/xfrout and the zone manager are only meaningful if the
         # xfrin/xfrout and the zone manager are only meaningful if the
         # authoritative server has been started.
         # authoritative server has been started.
         if self.cfg_start_auth:
         if self.cfg_start_auth:
-            self.start_xfrout(c_channel_env)
+            component_config['b10-xfrout'] = { 'kind': 'dispensable',
-            self.start_xfrin(c_channel_env)
+                                               'address': 'Xfrout' }
-            self.start_zonemgr(c_channel_env)
+            component_config['b10-xfrin'] = { 'kind': 'dispensable',
+                                              'address': 'Xfrin' }
+            component_config['b10-zonemgr'] = { 'kind': 'dispensable',
+                                              'address': 'Zonemgr' }
+            self.__propagate_component_config(component_config)
             self.started_auth_family = True
             self.started_auth_family = True
 
 
         # ... and finally start the remaining processes
         # ... and finally start the remaining processes
-        self.start_stats(c_channel_env)
+        component_config['b10-stats'] = { 'kind': 'dispensable',
-        self.start_stats_httpd(c_channel_env)
+                                          'address': 'Stats' }
-        self.start_cmdctl(c_channel_env)
+        component_config['b10-stats-httpd'] = { 'kind': 'dispensable',
+                                                'address': 'StatsHttpd' }
+        component_config['b10-cmdctl'] = { 'kind': 'needed',
+                                           'special': 'cmdctl' }
 
 
         if self.cfg_start_dhcp6:
         if self.cfg_start_dhcp6:
-            self.start_dhcp6(c_channel_env)
+            component_config['b10-dhcp6'] = { 'kind': 'dispensable',
+                                              'address': 'DHCP6' }
+
+        self.__propagate_component_config(component_config)
+
+        self.component_config = component_config
 
 
     def startup(self):
     def startup(self):
         """
         """
@@ -762,24 +789,9 @@ class BoB:
 
 
         # Started successfully
         # Started successfully
         self.runnable = True
         self.runnable = True
+        self.__started = True
         return None
         return None
 
 
-    def stop_all_processes(self):
-        """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()
-
     def stop_process(self, process, recipient):
     def stop_process(self, process, recipient):
         """
         """
         Stop the given process, friendly-like. The process is the name it has
         Stop the given process, friendly-like. The process is the name it has
@@ -793,6 +805,24 @@ class BoB:
         self.cc_session.group_sendmsg({'command': ['shutdown']}, recipient,
         self.cc_session.group_sendmsg({'command': ['shutdown']}, recipient,
             recipient)
             recipient)
 
 
+    def component_shutdown(self, exitcode=0):
+        """
+        Stop the Boss instance from a components' request. The exitcode
+        indicates the desired exit code.
+
+        If we did not start yet, it raises an exception, which is meant
+        to propagate through the component and configurator to the startup
+        routine and abort the startup imediatelly. If it is started up already,
+        we just mark it so we terminate soon.
+
+        It does set the exit code in both cases.
+        """
+        self.exitcode = exitcode
+        if not self.__started:
+            raise Exception("Component failed during startup");
+        else:
+            self.runnable = False
+
     # Series of stop_process wrappers
     # Series of stop_process wrappers
     def stop_resolver(self):
     def stop_resolver(self):
         self.stop_process('b10-resolver', 'Resolver')
         self.stop_process('b10-resolver', 'Resolver')
@@ -814,13 +844,13 @@ class BoB:
         logger.info(BIND10_SHUTDOWN)
         logger.info(BIND10_SHUTDOWN)
         # first try using the BIND 10 request to stop
         # first try using the BIND 10 request to stop
         try:
         try:
-            self.stop_all_processes()
+            self._component_configurator.shutdown()
         except:
         except:
             pass
             pass
         # XXX: some delay probably useful... how much is uncertain
         # 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.
         # still not enough.
-        time.sleep(1)  
+        time.sleep(1)
         self.reap_children()
         self.reap_children()
         # next try sending a SIGTERM
         # next try sending a SIGTERM
         processes_to_stop = list(self.processes.values())
         processes_to_stop = list(self.processes.values())
@@ -872,6 +902,9 @@ class BoB:
                     logger.fatal(BIND10_SOCKCREATOR_CRASHED)
                     logger.fatal(BIND10_SOCKCREATOR_CRASHED)
                     self.sockcreator = None
                     self.sockcreator = None
                     self.runnable = False
                     self.runnable = False
+                # This was inserted in self.processes by register_process.
+                # Now need to remove it.
+                del self.processes[pid]
             elif pid in self.processes:
             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)

+ 103 - 50
src/bin/bind10/tests/bind10_test.py.in

@@ -218,12 +218,28 @@ class MockBob(BoB):
         self.stats = False
         self.stats = False
         self.stats_httpd = False
         self.stats_httpd = False
         self.cmdctl = False
         self.cmdctl = False
+        self.dhcp6 = False
+        self.dhcp4 = False
         self.c_channel_env = {}
         self.c_channel_env = {}
         self.processes = { }
         self.processes = { }
         self.creator = False
         self.creator = False
 
 
+        class MockSockCreator(isc.bind10.component.Component):
+            def __init__(self, process, boss, kind, address=None, params=None):
+                isc.bind10.component.Component.__init__(self, process, boss,
+                                                        kind, 'SockCreator')
+                self._start_func = boss.start_creator
+
+        specials = isc.bind10.special_component.get_specials()
+        specials['sockcreator'] = MockSockCreator
+        self._component_configurator = \
+            isc.bind10.component.Configurator(self, specials)
+
     def start_creator(self):
     def start_creator(self):
         self.creator = True
         self.creator = True
+        procinfo = ProcessInfo('b10-sockcreator', ['/bin/false'])
+        procinfo.pid = 1
+        return procinfo
 
 
     def stop_creator(self, kill=False):
     def stop_creator(self, kill=False):
         self.creator = False
         self.creator = False
@@ -232,70 +248,103 @@ class MockBob(BoB):
         # Configuration options are set directly
         # Configuration options are set directly
         pass
         pass
 
 
-    def start_msgq(self, c_channel_env):
+    def start_msgq(self):
         self.msgq = True
         self.msgq = True
-        self.processes[2] = ProcessInfo('b10-msgq', ['/bin/false'])
+        procinfo = ProcessInfo('b10-msgq', ['/bin/false'])
-        self.processes[2].pid = 2
+        procinfo.pid = 2
-
+        return procinfo
-    def start_cfgmgr(self, c_channel_env):
-        self.cfgmgr = True
-        self.processes[3] = ProcessInfo('b10-cfgmgr', ['/bin/false'])
-        self.processes[3].pid = 3
 
 
     def start_ccsession(self, c_channel_env):
     def start_ccsession(self, c_channel_env):
+        # this is not a process, don't have to do anything with procinfo
         self.ccsession = True
         self.ccsession = True
-        self.processes[4] = ProcessInfo('b10-ccsession', ['/bin/false'])
-        self.processes[4].pid = 4
 
 
-    def start_auth(self, c_channel_env):
+    def start_cfgmgr(self):
+        self.cfgmgr = True
+        procinfo = ProcessInfo('b10-cfgmgr', ['/bin/false'])
+        procinfo.pid = 3
+        return procinfo
+
+    def start_auth(self):
         self.auth = True
         self.auth = True
-        self.processes[5] = ProcessInfo('b10-auth', ['/bin/false'])
+        procinfo = ProcessInfo('b10-auth', ['/bin/false'])
-        self.processes[5].pid = 5
+        procinfo.pid = 5
+        return procinfo
 
 
-    def start_resolver(self, c_channel_env):
+    def start_resolver(self):
         self.resolver = True
         self.resolver = True
-        self.processes[6] = ProcessInfo('b10-resolver', ['/bin/false'])
+        procinfo = ProcessInfo('b10-resolver', ['/bin/false'])
-        self.processes[6].pid = 6
+        procinfo.pid = 6
-
+        return procinfo
-    def start_xfrout(self, c_channel_env):
+
+    def start_simple(self, name):
+        procmap = { 'b10-xfrout': self.start_xfrout,
+                    'b10-xfrin': self.start_xfrin,
+                    'b10-zonemgr': self.start_zonemgr,
+                    'b10-stats': self.start_stats,
+                    'b10-stats-httpd': self.start_stats_httpd,
+                    'b10-cmdctl': self.start_cmdctl,
+                    'b10-dhcp6': self.start_dhcp6,
+                    'b10-dhcp4': self.start_dhcp4 }
+        return procmap[name]()
+
+    def start_xfrout(self):
         self.xfrout = True
         self.xfrout = True
-        self.processes[7] = ProcessInfo('b10-xfrout', ['/bin/false'])
+        procinfo = ProcessInfo('b10-xfrout', ['/bin/false'])
-        self.processes[7].pid = 7
+        procinfo.pid = 7
+        return procinfo
 
 
-    def start_xfrin(self, c_channel_env):
+    def start_xfrin(self):
         self.xfrin = True
         self.xfrin = True
-        self.processes[8] = ProcessInfo('b10-xfrin', ['/bin/false'])
+        procinfo = ProcessInfo('b10-xfrin', ['/bin/false'])
-        self.processes[8].pid = 8
+        procinfo.pid = 8
+        return procinfo
 
 
-    def start_zonemgr(self, c_channel_env):
+    def start_zonemgr(self):
         self.zonemgr = True
         self.zonemgr = True
-        self.processes[9] = ProcessInfo('b10-zonemgr', ['/bin/false'])
+        procinfo = ProcessInfo('b10-zonemgr', ['/bin/false'])
-        self.processes[9].pid = 9
+        procinfo.pid = 9
+        return procinfo
 
 
-    def start_stats(self, c_channel_env):
+    def start_stats(self):
         self.stats = True
         self.stats = True
-        self.processes[10] = ProcessInfo('b10-stats', ['/bin/false'])
+        procinfo = ProcessInfo('b10-stats', ['/bin/false'])
-        self.processes[10].pid = 10
+        procinfo.pid = 10
+        return procinfo
 
 
-    def start_stats_httpd(self, c_channel_env):
+    def start_stats_httpd(self):
         self.stats_httpd = True
         self.stats_httpd = True
-        self.processes[11] = ProcessInfo('b10-stats-httpd', ['/bin/false'])
+        procinfo = ProcessInfo('b10-stats-httpd', ['/bin/false'])
-        self.processes[11].pid = 11
+        procinfo.pid = 11
+        return procinfo
 
 
-    def start_cmdctl(self, c_channel_env):
+    def start_cmdctl(self):
         self.cmdctl = True
         self.cmdctl = True
-        self.processes[12] = ProcessInfo('b10-cmdctl', ['/bin/false'])
+        procinfo = ProcessInfo('b10-cmdctl', ['/bin/false'])
-        self.processes[12].pid = 12
+        procinfo.pid = 12
+        return procinfo
 
 
-    def start_dhcp6(self, c_channel_env):
+    def start_dhcp6(self):
-        self.dhcp6 = True
+        self.stats = True
-        self.processes[13] = ProcessInfo('b10-dhcp6', ['/bin/false'])
+        procinfo = ProcessInfo('b10-dhcp6', ['/bin/false'])
-        self.processes[13]
+        procinfo.pid = 13
+        return procinfo
 
 
-    def start_dhcp4(self, c_channel_env):
+    def start_dhcp4(self):
-        self.dhcp4 = True
+        self.stats = True
-        self.processes[14] = ProcessInfo('b10-dhcp4', ['/bin/false'])
+        procinfo = ProcessInfo('b10-dhcp4', ['/bin/false'])
-        self.processes[14]
+        procinfo.pid = 14
+        return procinfo
+
+    def stop_process(self, process, recipient):
+        procmap = { 'b10-auth': self.stop_auth,
+                    'b10-resolver': self.stop_resolver,
+                    'b10-xfrout': self.stop_xfrout,
+                    'b10-xfrin': self.stop_xfrin,
+                    'b10-zonemgr': self.stop_zonemgr,
+                    'b10-stats': self.stop_stats,
+                    'b10-stats-httpd': self.stop_stats_httpd,
+                    'b10-cmdctl': self.stop_cmdctl }
+        procmap[process]()
 
 
     # We don't really use all of these stop_ methods. But it might turn out
     # We don't really use all of these stop_ methods. But it might turn out
     # someone would add some stop_ method to BoB and we want that one overriden
     # someone would add some stop_ method to BoB and we want that one overriden
@@ -310,11 +359,6 @@ class MockBob(BoB):
             del self.processes[3]
             del self.processes[3]
         self.cfgmgr = False
         self.cfgmgr = False
 
 
-    def stop_ccsession(self):
-        if self.ccssession:
-            del self.processes[4]
-        self.ccsession = False
-
     def stop_auth(self):
     def stop_auth(self):
         if self.auth:
         if self.auth:
             del self.processes[5]
             del self.processes[5]
@@ -620,6 +664,15 @@ class TestStartStopProcessesBob(unittest.TestCase):
         bob.start_all_processes()
         bob.start_all_processes()
         self.check_started_dhcp(bob, False, False)
         self.check_started_dhcp(bob, False, False)
 
 
+    def test_start_dhcp_v6only(self):
+        # Create BoB and ensure correct initialization
+        bob = MockBob()
+        self.check_preconditions(bob)
+
+        # don't care about DNS stuff
+        bob.cfg_start_auth = False
+        bob.cfg_start_resolver = False
+
         # v6 only enabled
         # v6 only enabled
         bob.cfg_start_dhcp6 = True
         bob.cfg_start_dhcp6 = True
         bob.cfg_start_dhcp4 = False
         bob.cfg_start_dhcp4 = False
@@ -661,9 +714,9 @@ class TestBossCmd(unittest.TestCase):
         bob = MockBob()
         bob = MockBob()
         bob.start_all_processes()
         bob.start_all_processes()
         answer = bob.command_handler("show_processes", None)
         answer = bob.command_handler("show_processes", None)
-        processes = [[2, 'b10-msgq'],
+        processes = [[1, 'b10-sockcreator'],
+                     [2, 'b10-msgq'],
                      [3, 'b10-cfgmgr'], 
                      [3, 'b10-cfgmgr'], 
-                     [4, 'b10-ccsession'],
                      [5, 'b10-auth'],
                      [5, 'b10-auth'],
                      [7, 'b10-xfrout'],
                      [7, 'b10-xfrout'],
                      [8, 'b10-xfrin'], 
                      [8, 'b10-xfrin'],