BIND 10 master, updated. 586df2b37d5f26ac1998d12c86f280b11bf077b7 Changelog for #565
BIND 10 source code commits
bind10-changes at lists.isc.org
Thu Feb 24 13:22:01 UTC 2011
The branch, master has been updated
via 586df2b37d5f26ac1998d12c86f280b11bf077b7 (commit)
via 0ac0b4602fa30852b0d86cc3c0b4730deb1a58fe (commit)
via 34be7c60c8cd01a3693cdc35346ea8bed77a4c88 (commit)
via 008a3bf75b8aef0b813c5109fe8749f32ca6c7a9 (commit)
via cce105f44bf716ed738a1465e5412468d796aa13 (commit)
via e5961a4ce06bb430469c457856f5392ca147d857 (commit)
via 60f301c235b9d83b7fde6f06abac18d0a1168260 (commit)
via 4a8925ec51c064a456795ba17042bdf30ff2b8ab (commit)
via 34d182ec09a5674e87470772cce024d49043cbd9 (commit)
via f9e5f363f3abf3c08d65ff14421491b44ccbe8af (commit)
via 841627853b192480a8e663870ad3a1cb39bb724e (commit)
via 26aae7d612bf0f01b22a7c4784fffb909d148970 (commit)
via 5266058997a5746c04db5a721ac60630bbbc2abd (commit)
via a30321812264615d0f64271ce6ba5e841f7977a5 (commit)
via 93b246f4689918c081d9ed889cea9140b75adc1f (commit)
via 569afbc3c08776e04f1b755dce2ff5aa5c385647 (commit)
via 38778d44793426906ef7d0d25a70be4a36188765 (commit)
from 54f4650b7de4d275b29bc1d70b2cba98d59d305a (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 586df2b37d5f26ac1998d12c86f280b11bf077b7
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Thu Feb 24 14:21:25 2011 +0100
Changelog for #565
commit 0ac0b4602fa30852b0d86cc3c0b4730deb1a58fe
Merge: 54f4650b7de4d275b29bc1d70b2cba98d59d305a 34be7c60c8cd01a3693cdc35346ea8bed77a4c88
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Thu Feb 24 13:59:10 2011 +0100
Merge remote-tracking branch 'origin/trac565'
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 7 +
src/bin/bind10/bind10.py.in | 92 +++++++++++-
src/bin/bind10/tests/bind10_test.py | 283 ++++++++++++++++++++++++++---------
3 files changed, 303 insertions(+), 79 deletions(-)
-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index a0907da..cd94b2e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+ 179. [func] vorner
+ It is possible to start and stop resolver and authoritative
+ server without restart of the whole system. Change of the
+ configuration (Boss/start_auth and Boss/start_resolver) is
+ enough.
+ (Trac #565, git 0ac0b4602fa30852b0d86cc3c0b4730deb1a58fe)
+
178. [func] jelte
Resolver now makes (limited) use of the cache
(Trac #491, git 8b41f77f0099ddc7ca7d34d39ad8c39bb1a8363c)
diff --git a/src/bin/bind10/bind10.py.in b/src/bin/bind10/bind10.py.in
index 5685c05..c48a88c 100755
--- a/src/bin/bind10/bind10.py.in
+++ b/src/bin/bind10/bind10.py.in
@@ -209,23 +209,68 @@ class BoB:
self.ccs = None
self.cfg_start_auth = True
self.cfg_start_resolver = 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
self.verbose = verbose
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:
+ sys.stderr.write("[bind10] Starting " + name + " as " +
+ "a user, not root. This might fail.\n")
+ 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
if self.verbose:
sys.stdout.write("[bind10] Handling new configuration: " +
str(new_config) + "\n")
+ start_stop('resolver', self.started_resolver_family, resolver_on,
+ resolver_off)
+ start_stop('auth', self.started_auth_family, auth_on, auth_off)
+
answer = isc.config.ccsession.create_answer(0)
return answer
- # TODO
def command_handler(self, command, args):
if self.verbose:
@@ -464,11 +509,12 @@ class BoB:
# XXX: we hardcode port 8080
self.start_simple("b10-cmdctl", c_channel_env, 8080)
- def start_all_processes(self, c_channel_env):
+ def start_all_processes(self):
"""
Starts up all the processes. Any exception generated during the
starting of the processes is handled by the caller.
"""
+ 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)
@@ -485,6 +531,7 @@ class BoB:
# ... 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
@@ -498,6 +545,7 @@ class BoB:
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)
@@ -528,7 +576,8 @@ class BoB:
# Start all processes. If any one fails to start, kill all started
# processes and exit with an error indication.
try:
- self.start_all_processes(c_channel_env)
+ self.c_channel_env = c_channel_env
+ self.start_all_processes()
except Exception as e:
self.kill_started_processes()
return "Unable to start " + self.curproc + ": " + str(e)
@@ -550,10 +599,35 @@ class BoB:
self.cc_session.group_sendmsg(cmd, "Zonemgr", "Zonemgr")
self.cc_session.group_sendmsg(cmd, "Stats", "Stats")
- def stop_process(self, process):
- """Stop the given process, friendly-like."""
- # XXX nothing yet
- pass
+ def stop_process(self, process, recipient):
+ """
+ Stop the given process, friendly-like. The process is the name it has
+ (in logs, etc), the recipient is the address on msgq.
+ """
+ if self.verbose:
+ sys.stdout.write("[bind10] Asking %s to terminate\n" % 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):
"""Stop the BoB instance."""
@@ -659,6 +733,10 @@ 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):
diff --git a/src/bin/bind10/tests/bind10_test.py b/src/bin/bind10/tests/bind10_test.py
index 5b38913..ffa06bc 100644
--- a/src/bin/bind10/tests/bind10_test.py
+++ b/src/bin/bind10/tests/bind10_test.py
@@ -142,13 +142,13 @@ class TestBoB(unittest.TestCase):
self.assertEqual(bob.cfg_start_auth, True)
self.assertEqual(bob.cfg_start_resolver, False)
-# Class for testing the Bob.start_all_processes() method call.
+# Class for testing the BoB start/stop components routines.
#
# Although testing that external processes start is outside the scope
# of the unit test, by overriding the process start methods we can check
# that the right processes are started depending on the configuration
# options.
-class StartAllProcessesBob(BoB):
+class StartStopCheckBob(BoB):
def __init__(self):
BoB.__init__(self)
@@ -163,6 +163,7 @@ class StartAllProcessesBob(BoB):
self.zonemgr = False
self.stats = False
self.cmdctl = False
+ self.c_channel_env = {}
def read_bind10_config(self):
# Configuration options are set directly
@@ -198,118 +199,256 @@ class StartAllProcessesBob(BoB):
def start_cmdctl(self, c_channel_env):
self.cmdctl = True
-# Check that the start_all_processes method starts the right combination
-# of processes.
-class TestStartAllProcessesBob(unittest.TestCase):
+ # 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
+ # in case he forgets to update the tests.
+ def stop_msgq(self):
+ self.msgq = False
+
+ def stop_cfgmgr(self):
+ self.cfgmgr = False
+
+ def stop_ccsession(self):
+ self.ccsession = False
+
+ def stop_auth(self):
+ self.auth = False
+
+ def stop_resolver(self):
+ self.resolver = False
+
+ def stop_xfrout(self):
+ self.xfrout = False
+
+ def stop_xfrin(self):
+ self.xfrin = False
+
+ def stop_zonemgr(self):
+ self.zonemgr = False
+
+ def stop_stats(self):
+ self.stats = False
+
+ def stop_cmdctl(self):
+ self.cmdctl = False
+
+class TestStartStopProcessesBob(unittest.TestCase):
+ """
+ Check that the start_all_processes method starts the right combination
+ of processes and that the right processes are started and stopped
+ according to changes in configuration.
+ """
+ def check_started(self, bob, core, auth, resolver):
+ """
+ Check that the right sets of services are started. The ones that
+ should be running are specified by the core, auth and resolver parameters
+ (they are groups of processes, eg. auth means b10-auth, -xfrout, -xfrin
+ and -zonemgr).
+ """
+ self.assertEqual(bob.msgq, core)
+ self.assertEqual(bob.cfgmgr, core)
+ self.assertEqual(bob.ccsession, core)
+ self.assertEqual(bob.auth, auth)
+ self.assertEqual(bob.resolver, resolver)
+ self.assertEqual(bob.xfrout, auth)
+ self.assertEqual(bob.xfrin, auth)
+ self.assertEqual(bob.zonemgr, auth)
+ self.assertEqual(bob.stats, core)
+ self.assertEqual(bob.cmdctl, core)
+
def check_preconditions(self, bob):
- self.assertEqual(bob.msgq, False)
- self.assertEqual(bob.cfgmgr, False)
- self.assertEqual(bob.ccsession, False)
- self.assertEqual(bob.auth, False)
- self.assertEqual(bob.resolver, False)
- self.assertEqual(bob.xfrout, False)
- self.assertEqual(bob.xfrin, False)
- self.assertEqual(bob.zonemgr, False)
- self.assertEqual(bob.stats, False)
- self.assertEqual(bob.cmdctl, False)
+ self.check_started(bob, False, False, False)
+
+ def check_started_none(self, bob):
+ """
+ Check that the situation is according to configuration where no servers
+ should be started. Some processes still need to be running.
+ """
+ self.check_started(bob, True, False, False)
+
+ def check_started_both(self, bob):
+ """
+ Check the situation is according to configuration where both servers
+ (auth and resolver) are enabled.
+ """
+ self.check_started(bob, True, True, True)
+
+ def check_started_auth(self, bob):
+ """
+ Check the set of processes needed to run auth only is started.
+ """
+ self.check_started(bob, True, True, False)
+
+ def check_started_resolver(self, bob):
+ """
+ Check the set of processes needed to run resolver only is started.
+ """
+ self.check_started(bob, True, False, True)
# Checks the processes started when starting neither auth nor resolver
# is specified.
def test_start_none(self):
- # Created Bob and ensure initialization correct
- bob = StartAllProcessesBob()
+ # Create BoB and ensure correct initialization
+ bob = StartStopCheckBob()
self.check_preconditions(bob)
# Start processes and check what was started
- c_channel_env = {}
bob.cfg_start_auth = False
bob.cfg_start_resolver = False
- bob.start_all_processes(c_channel_env)
-
- self.assertEqual(bob.msgq, True)
- self.assertEqual(bob.cfgmgr, True)
- self.assertEqual(bob.ccsession, True)
- self.assertEqual(bob.auth, False)
- self.assertEqual(bob.resolver, False)
- self.assertEqual(bob.xfrout, False)
- self.assertEqual(bob.xfrin, False)
- self.assertEqual(bob.zonemgr, False)
- self.assertEqual(bob.stats, True)
- self.assertEqual(bob.cmdctl, True)
+ bob.start_all_processes()
+ self.check_started_none(bob)
# Checks the processes started when starting only the auth process
def test_start_auth(self):
- # Created Bob and ensure initialization correct
- bob = StartAllProcessesBob()
+ # Create BoB and ensure correct initialization
+ bob = StartStopCheckBob()
self.check_preconditions(bob)
# Start processes and check what was started
- c_channel_env = {}
bob.cfg_start_auth = True
bob.cfg_start_resolver = False
- bob.start_all_processes(c_channel_env)
+ bob.start_all_processes()
- self.assertEqual(bob.msgq, True)
- self.assertEqual(bob.cfgmgr, True)
- self.assertEqual(bob.ccsession, True)
- self.assertEqual(bob.auth, True)
- self.assertEqual(bob.resolver, False)
- self.assertEqual(bob.xfrout, True)
- self.assertEqual(bob.xfrin, True)
- self.assertEqual(bob.zonemgr, True)
- self.assertEqual(bob.stats, True)
- self.assertEqual(bob.cmdctl, True)
+ self.check_started_auth(bob)
# Checks the processes started when starting only the resolver process
def test_start_resolver(self):
- # Created Bob and ensure initialization correct
- bob = StartAllProcessesBob()
+ # Create BoB and ensure correct initialization
+ bob = StartStopCheckBob()
self.check_preconditions(bob)
# Start processes and check what was started
- c_channel_env = {}
bob.cfg_start_auth = False
bob.cfg_start_resolver = True
- bob.start_all_processes(c_channel_env)
+ bob.start_all_processes()
- self.assertEqual(bob.msgq, True)
- self.assertEqual(bob.cfgmgr, True)
- self.assertEqual(bob.ccsession, True)
- self.assertEqual(bob.auth, False)
- self.assertEqual(bob.resolver, True)
- self.assertEqual(bob.xfrout, False)
- self.assertEqual(bob.xfrin, False)
- self.assertEqual(bob.zonemgr, False)
- self.assertEqual(bob.stats, True)
- self.assertEqual(bob.cmdctl, True)
+ self.check_started_resolver(bob)
# Checks the processes started when starting both auth and resolver process
def test_start_both(self):
- # Created Bob and ensure initialization correct
- bob = StartAllProcessesBob()
+ # Create BoB and ensure correct initialization
+ bob = StartStopCheckBob()
self.check_preconditions(bob)
# Start processes and check what was started
- c_channel_env = {}
bob.cfg_start_auth = True
bob.cfg_start_resolver = True
- bob.start_all_processes(c_channel_env)
+ bob.start_all_processes()
+
+ self.check_started_both(bob)
+
+ def test_config_start(self):
+ """
+ Test that the configuration starts and stops processes according
+ to configuration changes.
+ """
+
+ # Create BoB and ensure correct initialization
+ bob = StartStopCheckBob()
+ self.check_preconditions(bob)
+
+ # Start processes (nothing much should be started, as in
+ # test_start_none)
+ bob.cfg_start_auth = False
+ bob.cfg_start_resolver = False
+
+ bob.start_all_processes()
+ bob.runnable = True
+ self.check_started_none(bob)
+
+ # Enable both at once
+ bob.config_handler({'start_auth': True, 'start_resolver': True})
+ self.check_started_both(bob)
+
+ # Not touched by empty change
+ bob.config_handler({})
+ self.check_started_both(bob)
+
+ # Not touched by change to the same configuration
+ bob.config_handler({'start_auth': True, 'start_resolver': True})
+ self.check_started_both(bob)
+
+ # Turn them both off again
+ bob.config_handler({'start_auth': False, 'start_resolver': False})
+ self.check_started_none(bob)
+
+ # Not touched by empty change
+ bob.config_handler({})
+ self.check_started_none(bob)
+
+ # Not touched by change to the same configuration
+ bob.config_handler({'start_auth': False, 'start_resolver': False})
+ self.check_started_none(bob)
+
+ # Start and stop auth separately
+ bob.config_handler({'start_auth': True})
+ self.check_started_auth(bob)
+
+ bob.config_handler({'start_auth': False})
+ self.check_started_none(bob)
+
+ # Start and stop resolver separately
+ bob.config_handler({'start_resolver': True})
+ self.check_started_resolver(bob)
+
+ bob.config_handler({'start_resolver': False})
+ self.check_started_none(bob)
+
+ # Alternate
+ bob.config_handler({'start_auth': True})
+ self.check_started_auth(bob)
+
+ bob.config_handler({'start_auth': False, 'start_resolver': True})
+ self.check_started_resolver(bob)
+
+ bob.config_handler({'start_auth': True, 'start_resolver': False})
+ self.check_started_auth(bob)
+
+ def test_config_start_once(self):
+ """
+ Tests that a process is started only once.
+ """
+ # Create BoB and ensure correct initialization
+ bob = StartStopCheckBob()
+ self.check_preconditions(bob)
+
+ # Start processes (both)
+ bob.cfg_start_auth = True
+ bob.cfg_start_resolver = True
+
+ bob.start_all_processes()
+ bob.runnable = True
+ self.check_started_both(bob)
+
+ bob.start_auth = lambda: self.fail("Started auth again")
+ bob.start_xfrout = lambda: self.fail("Started xfrout again")
+ bob.start_xfrin = lambda: self.fail("Started xfrin again")
+ bob.start_zonemgr = lambda: self.fail("Started zonemgr again")
+ bob.start_resolver = lambda: self.fail("Started resolver again")
+
+ # Send again we want to start them. Should not do it, as they are.
+ bob.config_handler({'start_auth': True})
+ bob.config_handler({'start_resolver': True})
+
+ def test_config_not_started_early(self):
+ """
+ Test that processes are not started by the config handler before
+ startup.
+ """
+ bob = StartStopCheckBob()
+ self.check_preconditions(bob)
- self.assertEqual(bob.msgq, True)
- self.assertEqual(bob.cfgmgr, True)
- self.assertEqual(bob.ccsession, True)
- self.assertEqual(bob.auth, True)
- self.assertEqual(bob.resolver, True)
- self.assertEqual(bob.xfrout, True)
- self.assertEqual(bob.xfrin, True)
- self.assertEqual(bob.zonemgr, True)
- self.assertEqual(bob.stats, True)
- self.assertEqual(bob.cmdctl, True)
+ bob.start_auth = lambda: self.fail("Started auth again")
+ bob.start_xfrout = lambda: self.fail("Started xfrout again")
+ bob.start_xfrin = lambda: self.fail("Started xfrin again")
+ bob.start_zonemgr = lambda: self.fail("Started zonemgr again")
+ bob.start_resolver = lambda: self.fail("Started resolver again")
+ bob.config_handler({'start_auth': True, 'start_resolver': True})
if __name__ == '__main__':
unittest.main()
More information about the bind10-changes
mailing list