Parcourir la source

[master] Merge branch 'trac2967'

Paul Selkirk il y a 11 ans
Parent
commit
4c9ef29631

+ 66 - 71
src/bin/zonemgr/tests/zonemgr_test.py

@@ -1,4 +1,4 @@
-# Copyright (C) 2010  Internet Systems Consortium.
+# Copyright (C) 2010-2013  Internet Systems Consortium.
 #
 #
 # Permission to use, copy, modify, and distribute this software for any
 # Permission to use, copy, modify, and distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
 # purpose with or without fee is hereby granted, provided that the above
@@ -22,6 +22,7 @@ import tempfile
 from zonemgr import *
 from zonemgr import *
 from isc.testutils.ccsession_mock import MockModuleCCSession
 from isc.testutils.ccsession_mock import MockModuleCCSession
 from isc.notify import notify_out
 from isc.notify import notify_out
+from isc.datasrc import ZoneFinder
 
 
 ZONE_NAME_CLASS1_IN = ("example.net.", "IN")
 ZONE_NAME_CLASS1_IN = ("example.net.", "IN")
 ZONE_NAME_CLASS1_CH = ("example.net.", "CH")
 ZONE_NAME_CLASS1_CH = ("example.net.", "CH")
@@ -36,8 +37,6 @@ LOWERBOUND_RETRY = 5
 REFRESH_JITTER = 0.10
 REFRESH_JITTER = 0.10
 RELOAD_JITTER = 0.75
 RELOAD_JITTER = 0.75
 
 
-TEST_SQLITE3_DBFILE = os.getenv("TESTDATAOBJDIR") + '/initdb.file'
-
 class ZonemgrTestException(Exception):
 class ZonemgrTestException(Exception):
     pass
     pass
 
 
@@ -46,16 +45,53 @@ class FakeCCSession(isc.config.ConfigData, MockModuleCCSession):
         module_spec = isc.config.module_spec_from_file(SPECFILE_LOCATION)
         module_spec = isc.config.module_spec_from_file(SPECFILE_LOCATION)
         ConfigData.__init__(self, module_spec)
         ConfigData.__init__(self, module_spec)
         MockModuleCCSession.__init__(self)
         MockModuleCCSession.__init__(self)
+        # For inspection
+        self.added_remote_modules = []
+
+    def add_remote_config_by_name(self, name, callback):
+        self.added_remote_modules.append((name, callback))
 
 
     def rpc_call(self, command, module, instance="*", to="*", params=None):
     def rpc_call(self, command, module, instance="*", to="*", params=None):
         if module not in ("Auth", "Xfrin"):
         if module not in ("Auth", "Xfrin"):
             raise ZonemgrTestException("module name not exist")
             raise ZonemgrTestException("module name not exist")
 
 
-    def get_remote_config_value(self, module_name, identifier):
-        if module_name == "Auth" and identifier == "database_file":
-            return TEST_SQLITE3_DBFILE, False
+class MockDataSourceClient():
+    '''A simple mock data source client.'''
+    def __init__(self):
+        self.rdata_net = 'a.example.net. root.example.net. 2009073106 ' + \
+            '7200 3600 2419200 21600'
+        self.rdata_org = 'a.example.org. root.example.org. 2009073112 ' + \
+            '7200 3600 2419200 21600'
+
+    def find_zone(self, zone_name):
+        '''Mock version of DataSourceClient.find_zone().'''
+        return (isc.datasrc.DataSourceClient.SUCCESS, self)
+
+    def find(self, name, rrtype, options=ZoneFinder.FIND_DEFAULT):
+        '''Mock version of ZoneFinder.find().'''
+        if name == Name('example.net'):
+            rdata = Rdata(RRType.SOA, RRClass.IN, self.rdata_net)
+        elif name == 'example.org.':
+            rdata = Rdata(RRType.SOA, RRClass.IN, self.rdata_org)
         else:
         else:
-            return "unknown", False
+            return (ZoneFinder.NXDOMAIN, None, 0)
+        rrset = RRset(name, RRClass.IN, RRType.SOA, RRTTL(3600))
+        rrset.add_rdata(rdata)
+        return (ZoneFinder.SUCCESS, rrset, 0)
+
+class MockDataSrcClientsMgr():
+    '''A simple mock data source client manager.'''
+    def __init__(self):
+        self.datasrc_client = MockDataSourceClient()
+
+    def get_client_list(self, rrclass):
+        return self
+
+    def find(self, zone_name, want_exact_match, want_finder):
+        """Pretending find method on the object returned by get_client_list"""
+        if issubclass(type(self.datasrc_client), Exception):
+            raise self.datasrc_client
+        return self.datasrc_client, None, None
 
 
 class MyZonemgrRefresh(ZonemgrRefresh):
 class MyZonemgrRefresh(ZonemgrRefresh):
     def __init__(self):
     def __init__(self):
@@ -66,19 +102,8 @@ class MyZonemgrRefresh(ZonemgrRefresh):
         self._reload_jitter = 0.75
         self._reload_jitter = 0.75
         self._refresh_jitter = 0.25
         self._refresh_jitter = 0.25
 
 
-        def get_zone_soa(zone_name, db_file):
-            if zone_name == 'example.net.':
-                return (1, 2, 'example.net.', 'example.net.sd.', 21600, 'SOA', None,
-                        'a.example.net. root.example.net. 2009073106 7200 3600 2419200 21600')
-            elif zone_name == 'example.org.':
-                return (1, 2, 'example.org.', 'example.org.sd.', 21600, 'SOA', None,
-                        'a.example.org. root.example.org. 2009073112 7200 3600 2419200 21600')
-            else:
-                return None
-        sqlite3_ds.get_zone_soa = get_zone_soa
-
-        ZonemgrRefresh.__init__(self, TEST_SQLITE3_DBFILE, self._slave_socket,
-                                FakeCCSession())
+        ZonemgrRefresh.__init__(self, self._slave_socket, FakeCCSession())
+        self._datasrc_clients_mgr = MockDataSrcClientsMgr()
         current_time = time.time()
         current_time = time.time()
         self._zonemgr_refresh_info = {
         self._zonemgr_refresh_info = {
          ('example.net.', 'IN'): {
          ('example.net.', 'IN'): {
@@ -95,19 +120,23 @@ class MyZonemgrRefresh(ZonemgrRefresh):
 
 
 class TestZonemgrRefresh(unittest.TestCase):
 class TestZonemgrRefresh(unittest.TestCase):
     def setUp(self):
     def setUp(self):
-        if os.path.exists(TEST_SQLITE3_DBFILE):
-            os.unlink(TEST_SQLITE3_DBFILE)
         self.stderr_backup = sys.stderr
         self.stderr_backup = sys.stderr
         sys.stderr = open(os.devnull, 'w')
         sys.stderr = open(os.devnull, 'w')
         self.zone_refresh = MyZonemgrRefresh()
         self.zone_refresh = MyZonemgrRefresh()
         self.cc_session = FakeCCSession()
         self.cc_session = FakeCCSession()
 
 
     def tearDown(self):
     def tearDown(self):
-        if os.path.exists(TEST_SQLITE3_DBFILE):
-            os.unlink(TEST_SQLITE3_DBFILE)
         sys.stderr.close()
         sys.stderr.close()
         sys.stderr = self.stderr_backup
         sys.stderr = self.stderr_backup
 
 
+    def test_init(self):
+        """Check some initial configuration after construction"""
+        # data source "module" should have been registrered as a necessary
+        # remote config
+        self.assertEqual([('data_sources',
+                           self.zone_refresh._datasrc_config_handler)],
+                         self.zone_refresh._module_cc.added_remote_modules)
+
     def test_random_jitter(self):
     def test_random_jitter(self):
         max = 100025.120
         max = 100025.120
         jitter = 0
         jitter = 0
@@ -195,16 +224,9 @@ class TestZonemgrRefresh(unittest.TestCase):
 
 
     def test_zonemgr_reload_zone(self):
     def test_zonemgr_reload_zone(self):
         soa_rdata = 'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600'
         soa_rdata = 'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600'
-        # We need to restore this not to harm other tests
-        old_get_zone_soa = sqlite3_ds.get_zone_soa
-        def get_zone_soa(zone_name, db_file):
-            return (1, 2, 'example.net.', 'example.net.sd.', 21600, 'SOA', None,
-                    'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600')
-        sqlite3_ds.get_zone_soa = get_zone_soa
-
+        self.zone_refresh._datasrc_clients_mgr.datasrc_client.rdata_net = soa_rdata
         self.zone_refresh.zonemgr_reload_zone(ZONE_NAME_CLASS1_IN)
         self.zone_refresh.zonemgr_reload_zone(ZONE_NAME_CLASS1_IN)
         self.assertEqual(soa_rdata, self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_soa_rdata"])
         self.assertEqual(soa_rdata, self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_soa_rdata"])
-        sqlite3_ds.get_zone_soa = old_get_zone_soa
 
 
     def test_get_zone_notifier_master(self):
     def test_get_zone_notifier_master(self):
         notify_master = "192.168.1.1"
         notify_master = "192.168.1.1"
@@ -275,24 +297,10 @@ class TestZonemgrRefresh(unittest.TestCase):
     def test_send_command(self):
     def test_send_command(self):
         self.assertRaises(ZonemgrTestException, self.zone_refresh._send_command, "Unknown", "Notify", None)
         self.assertRaises(ZonemgrTestException, self.zone_refresh._send_command, "Unknown", "Notify", None)
 
 
-    def test_zone_mgr_is_empty(self):
-        self.assertFalse(self.zone_refresh._zone_mgr_is_empty())
-        self.zone_refresh._zonemgr_refresh_info = {}
-        self.assertTrue(self.zone_refresh._zone_mgr_is_empty())
-
     def test_zonemgr_add_zone(self):
     def test_zonemgr_add_zone(self):
         soa_rdata = 'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600'
         soa_rdata = 'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600'
-        # This needs to be restored. The following test actually failed if we left
-        # this unclean
-        old_get_zone_soa = sqlite3_ds.get_zone_soa
+        self.zone_refresh._datasrc_clients_mgr.datasrc_client.rdata_net = soa_rdata
         time1 = time.time()
         time1 = time.time()
-
-        def get_zone_soa(zone_name, db_file):
-            return (1, 2, 'example.net.', 'example.net.sd.', 21600, 'SOA', None,
-                    'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600')
-
-        sqlite3_ds.get_zone_soa = get_zone_soa
-
         self.zone_refresh._zonemgr_refresh_info = {}
         self.zone_refresh._zonemgr_refresh_info = {}
         self.zone_refresh.zonemgr_add_zone(ZONE_NAME_CLASS1_IN)
         self.zone_refresh.zonemgr_add_zone(ZONE_NAME_CLASS1_IN)
         self.assertEqual(1, len(self.zone_refresh._zonemgr_refresh_info))
         self.assertEqual(1, len(self.zone_refresh._zonemgr_refresh_info))
@@ -306,12 +314,13 @@ class TestZonemgrRefresh(unittest.TestCase):
         self.assertTrue((time1 + 900 * (1 - self.zone_refresh._reload_jitter)) <= zone_timeout)
         self.assertTrue((time1 + 900 * (1 - self.zone_refresh._reload_jitter)) <= zone_timeout)
         self.assertTrue(zone_timeout <= time2 + 900)
         self.assertTrue(zone_timeout <= time2 + 900)
 
 
-        def get_zone_soa2(zone_name, db_file):
+        old_get_zone_soa = self.zone_refresh._get_zone_soa
+        def get_zone_soa2(zone_name_class):
             return None
             return None
-        sqlite3_ds.get_zone_soa = get_zone_soa2
+        self.zone_refresh._get_zone_soa = get_zone_soa2
         self.zone_refresh.zonemgr_add_zone(ZONE_NAME_CLASS2_IN)
         self.zone_refresh.zonemgr_add_zone(ZONE_NAME_CLASS2_IN)
         self.assertTrue(self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS2_IN]["zone_soa_rdata"] is None)
         self.assertTrue(self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS2_IN]["zone_soa_rdata"] is None)
-        sqlite3_ds.get_zone_soa = old_get_zone_soa
+        self.zone_refresh._get_zone_soa = old_get_zone_soa
 
 
     def test_zone_handle_notify(self):
     def test_zone_handle_notify(self):
         self.assertTrue(self.zone_refresh.zone_handle_notify(
         self.assertTrue(self.zone_refresh.zone_handle_notify(
@@ -333,10 +342,7 @@ class TestZonemgrRefresh(unittest.TestCase):
 
 
     def test_zone_refresh_success(self):
     def test_zone_refresh_success(self):
         soa_rdata = 'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600'
         soa_rdata = 'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600'
-        def get_zone_soa(zone_name, db_file):
-            return (1, 2, 'example.net.', 'example.net.sd.', 21600, 'SOA', None,
-                    'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600')
-        sqlite3_ds.get_zone_soa = get_zone_soa
+        self.zone_refresh._datasrc_clients_mgr.datasrc_client.rdata_net = soa_rdata
         time1 = time.time()
         time1 = time.time()
         self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"] = ZONE_REFRESHING
         self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"] = ZONE_REFRESHING
         self.zone_refresh.zone_refresh_success(ZONE_NAME_CLASS1_IN)
         self.zone_refresh.zone_refresh_success(ZONE_NAME_CLASS1_IN)
@@ -373,14 +379,14 @@ class TestZonemgrRefresh(unittest.TestCase):
         self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_fail, ZONE_NAME_CLASS3_CH)
         self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_fail, ZONE_NAME_CLASS3_CH)
         self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_fail, ZONE_NAME_CLASS3_IN)
         self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_fail, ZONE_NAME_CLASS3_IN)
 
 
-        old_get_zone_soa = sqlite3_ds.get_zone_soa
-        def get_zone_soa(zone_name, db_file):
+        old_get_zone_soa = self.zone_refresh._get_zone_soa
+        def get_zone_soa(zone_name_class):
             return None
             return None
-        sqlite3_ds.get_zone_soa = get_zone_soa
+        self.zone_refresh._get_zone_soa = get_zone_soa
         self.zone_refresh.zone_refresh_fail(ZONE_NAME_CLASS1_IN)
         self.zone_refresh.zone_refresh_fail(ZONE_NAME_CLASS1_IN)
         self.assertEqual(self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"],
         self.assertEqual(self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"],
                          ZONE_EXPIRED)
                          ZONE_EXPIRED)
-        sqlite3_ds.get_zone_soa = old_get_zone_soa
+        self.zone_refresh._get_zone_soa = old_get_zone_soa
 
 
     def test_find_need_do_refresh_zone(self):
     def test_find_need_do_refresh_zone(self):
         time1 = time.time()
         time1 = time.time()
@@ -628,7 +634,6 @@ class MyZonemgr(Zonemgr):
         def __exit__(self, type, value, traceback): pass
         def __exit__(self, type, value, traceback): pass
 
 
     def __init__(self):
     def __init__(self):
-        self._db_file = TEST_SQLITE3_DBFILE
         self._zone_refresh = None
         self._zone_refresh = None
         self._shutdown_event = threading.Event()
         self._shutdown_event = threading.Event()
         self._module_cc = FakeCCSession()
         self._module_cc = FakeCCSession()
@@ -649,14 +654,8 @@ class MyZonemgr(Zonemgr):
 class TestZonemgr(unittest.TestCase):
 class TestZonemgr(unittest.TestCase):
 
 
     def setUp(self):
     def setUp(self):
-        if os.path.exists(TEST_SQLITE3_DBFILE):
-            os.unlink(TEST_SQLITE3_DBFILE)
         self.zonemgr = MyZonemgr()
         self.zonemgr = MyZonemgr()
 
 
-    def tearDown(self):
-        if os.path.exists(TEST_SQLITE3_DBFILE):
-            os.unlink(TEST_SQLITE3_DBFILE)
-
     def test_config_handler(self):
     def test_config_handler(self):
         config_data1 = {
         config_data1 = {
                     "lowerbound_refresh" : 60,
                     "lowerbound_refresh" : 60,
@@ -676,9 +675,8 @@ class TestZonemgr(unittest.TestCase):
         config_data3 = {"refresh_jitter" : 0.7}
         config_data3 = {"refresh_jitter" : 0.7}
         self.zonemgr.config_handler(config_data3)
         self.zonemgr.config_handler(config_data3)
         self.assertEqual(0.5, self.zonemgr._config_data.get("refresh_jitter"))
         self.assertEqual(0.5, self.zonemgr._config_data.get("refresh_jitter"))
-        # The zone doesn't exist in database, simply skip loading soa for it and log an warning
-        self.zonemgr._zone_refresh = ZonemgrRefresh(TEST_SQLITE3_DBFILE, None,
-                                                    FakeCCSession())
+        # The zone doesn't exist in database, simply skip loading soa for it and log a warning
+        self.zonemgr._zone_refresh = ZonemgrRefresh(None, FakeCCSession())
         config_data1["secondary_zones"] = [{"name": "nonexistent.example",
         config_data1["secondary_zones"] = [{"name": "nonexistent.example",
                                             "class": "IN"}]
                                             "class": "IN"}]
         self.assertEqual(self.zonemgr.config_handler(config_data1),
         self.assertEqual(self.zonemgr.config_handler(config_data1),
@@ -689,9 +687,6 @@ class TestZonemgr(unittest.TestCase):
                         is None)
                         is None)
         self.assertEqual(0.1, self.zonemgr._config_data.get("refresh_jitter"))
         self.assertEqual(0.1, self.zonemgr._config_data.get("refresh_jitter"))
 
 
-    def test_get_db_file(self):
-        self.assertEqual(TEST_SQLITE3_DBFILE, self.zonemgr.get_db_file())
-
     def test_parse_cmd_params(self):
     def test_parse_cmd_params(self):
         params1 = {"zone_name" : "example.com.", "zone_class" : "CH",
         params1 = {"zone_name" : "example.com.", "zone_class" : "CH",
                    "master" : "127.0.0.1"}
                    "master" : "127.0.0.1"}

+ 166 - 86
src/bin/zonemgr/zonemgr.py.in

@@ -1,6 +1,6 @@
 #!@PYTHON@
 #!@PYTHON@
 
 
-# Copyright (C) 2010  Internet Systems Consortium.
+# Copyright (C) 2010-2013  Internet Systems Consortium.
 #
 #
 # Permission to use, copy, modify, and distribute this software for any
 # Permission to use, copy, modify, and distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
 # purpose with or without fee is hereby granted, provided that the above
@@ -34,12 +34,14 @@ import threading
 import select
 import select
 import socket
 import socket
 import errno
 import errno
-from isc.datasrc import sqlite3_ds
 from optparse import OptionParser, OptionValueError
 from optparse import OptionParser, OptionValueError
 from isc.config.ccsession import *
 from isc.config.ccsession import *
 import isc.util.process
 import isc.util.process
 from isc.log_messages.zonemgr_messages import *
 from isc.log_messages.zonemgr_messages import *
 from isc.notify import notify_out
 from isc.notify import notify_out
+from isc.server_common.datasrc_clients_mgr import DataSrcClientsMgr, ConfigError
+from isc.datasrc import DataSourceClient, ZoneFinder
+from isc.dns import *
 
 
 # Initialize logging for called modules.
 # Initialize logging for called modules.
 isc.log.init("b10-zonemgr", buffer=True)
 isc.log.init("b10-zonemgr", buffer=True)
@@ -66,7 +68,9 @@ if "B10_FROM_BUILD" in os.environ:
 else:
 else:
     PREFIX = "@prefix@"
     PREFIX = "@prefix@"
     DATAROOTDIR = "@datarootdir@"
     DATAROOTDIR = "@datarootdir@"
-    SPECFILE_PATH = "@datadir@/@PACKAGE@".replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
+    SPECFILE_PATH = "@datadir@/@PACKAGE@".replace("${datarootdir}",
+                                          DATAROOTDIR).replace("${prefix}",
+                                                               PREFIX)
     AUTH_SPECFILE_PATH = SPECFILE_PATH
     AUTH_SPECFILE_PATH = SPECFILE_PATH
 
 
 SPECFILE_LOCATION = SPECFILE_PATH + "/zonemgr.spec"
 SPECFILE_LOCATION = SPECFILE_PATH + "/zonemgr.spec"
@@ -76,7 +80,6 @@ __version__ = "BIND10"
 
 
 # define module name
 # define module name
 XFRIN_MODULE_NAME = 'Xfrin'
 XFRIN_MODULE_NAME = 'Xfrin'
-AUTH_MODULE_NAME = 'Auth'
 
 
 # define command name
 # define command name
 ZONE_REFRESH_COMMAND = 'refresh_from_zonemgr'
 ZONE_REFRESH_COMMAND = 'refresh_from_zonemgr'
@@ -103,19 +106,24 @@ class ZonemgrRefresh:
     can be stopped by calling shutdown() in another thread.
     can be stopped by calling shutdown() in another thread.
     """
     """
 
 
-    def __init__(self, db_file, slave_socket, module_cc_session):
-        self._mccs = module_cc_session
+    def __init__(self, slave_socket, module_cc):
+        self._module_cc = module_cc
         self._check_sock = slave_socket
         self._check_sock = slave_socket
-        self._db_file = db_file
         self._zonemgr_refresh_info = {}
         self._zonemgr_refresh_info = {}
         self._lowerbound_refresh = None
         self._lowerbound_refresh = None
         self._lowerbound_retry = None
         self._lowerbound_retry = None
         self._max_transfer_timeout = None
         self._max_transfer_timeout = None
         self._refresh_jitter = None
         self._refresh_jitter = None
         self._reload_jitter = None
         self._reload_jitter = None
-        self.update_config_data(module_cc_session.get_full_config(),
-                                module_cc_session)
+        self.update_config_data(module_cc.get_full_config(), module_cc)
         self._running = False
         self._running = False
+        # This is essentially private, but we allow tests to customize it.
+        self._datasrc_clients_mgr = DataSrcClientsMgr()
+        # data_sources configuration should be ready with cfgmgr, so this
+        # shouldn't fail; if it ever does we simply propagate the exception
+        # to terminate the program.
+        self._module_cc.add_remote_config_by_name('data_sources',
+                                                  self._datasrc_config_handler)
 
 
     def _random_jitter(self, max, jitter):
     def _random_jitter(self, max, jitter):
         """Imposes some random jitters for refresh and
         """Imposes some random jitters for refresh and
@@ -133,27 +141,32 @@ class ZonemgrRefresh:
     def _set_zone_timer(self, zone_name_class, max, jitter):
     def _set_zone_timer(self, zone_name_class, max, jitter):
         """Set zone next refresh time.
         """Set zone next refresh time.
         jitter should not be bigger than half the original value."""
         jitter should not be bigger than half the original value."""
-        self._set_zone_next_refresh_time(zone_name_class, self._get_current_time() + \
+        self._set_zone_next_refresh_time(zone_name_class,
+                                         self._get_current_time() +
                                             self._random_jitter(max, jitter))
                                             self._random_jitter(max, jitter))
 
 
     def _set_zone_refresh_timer(self, zone_name_class):
     def _set_zone_refresh_timer(self, zone_name_class):
         """Set zone next refresh time after zone refresh success.
         """Set zone next refresh time after zone refresh success.
            now + refresh - refresh_jitter <= next_refresh_time <= now + refresh
            now + refresh - refresh_jitter <= next_refresh_time <= now + refresh
            """
            """
-        zone_refresh_time = float(self._get_zone_soa_rdata(zone_name_class).split(" ")[REFRESH_OFFSET])
+        zone_refresh_time = float(self._get_zone_soa_rdata(zone_name_class).
+                                      split(" ")[REFRESH_OFFSET])
         zone_refresh_time = max(self._lowerbound_refresh, zone_refresh_time)
         zone_refresh_time = max(self._lowerbound_refresh, zone_refresh_time)
-        self._set_zone_timer(zone_name_class, zone_refresh_time, self._refresh_jitter * zone_refresh_time)
+        self._set_zone_timer(zone_name_class, zone_refresh_time,
+                             self._refresh_jitter * zone_refresh_time)
 
 
     def _set_zone_retry_timer(self, zone_name_class):
     def _set_zone_retry_timer(self, zone_name_class):
         """Set zone next refresh time after zone refresh fail.
         """Set zone next refresh time after zone refresh fail.
            now + retry - retry_jitter <= next_refresh_time <= now + retry
            now + retry - retry_jitter <= next_refresh_time <= now + retry
            """
            """
-        if (self._get_zone_soa_rdata(zone_name_class) is not None):
-            zone_retry_time = float(self._get_zone_soa_rdata(zone_name_class).split(" ")[RETRY_OFFSET])
+        if self._get_zone_soa_rdata(zone_name_class) is not None:
+            zone_retry_time = float(self._get_zone_soa_rdata(zone_name_class).
+                                        split(" ")[RETRY_OFFSET])
         else:
         else:
             zone_retry_time = 0.0
             zone_retry_time = 0.0
         zone_retry_time = max(self._lowerbound_retry, zone_retry_time)
         zone_retry_time = max(self._lowerbound_retry, zone_retry_time)
-        self._set_zone_timer(zone_name_class, zone_retry_time, self._refresh_jitter * zone_retry_time)
+        self._set_zone_timer(zone_name_class, zone_retry_time,
+                             self._refresh_jitter * zone_retry_time)
 
 
     def _set_zone_notify_timer(self, zone_name_class):
     def _set_zone_notify_timer(self, zone_name_class):
         """Set zone next refresh time after receiving notify
         """Set zone next refresh time after receiving notify
@@ -167,19 +180,22 @@ class ZonemgrRefresh:
 
 
     def zone_refresh_success(self, zone_name_class):
     def zone_refresh_success(self, zone_name_class):
         """Update zone info after zone refresh success"""
         """Update zone info after zone refresh success"""
-        if (self._zone_not_exist(zone_name_class)):
-            logger.error(ZONEMGR_UNKNOWN_ZONE_SUCCESS, zone_name_class[0], zone_name_class[1])
+        if self._zone_not_exist(zone_name_class):
+            logger.error(ZONEMGR_UNKNOWN_ZONE_SUCCESS, zone_name_class[0],
+                         zone_name_class[1])
             raise ZonemgrException("[b10-zonemgr] Zone (%s, %s) doesn't "
             raise ZonemgrException("[b10-zonemgr] Zone (%s, %s) doesn't "
                                    "belong to zonemgr" % zone_name_class)
                                    "belong to zonemgr" % zone_name_class)
         self.zonemgr_reload_zone(zone_name_class)
         self.zonemgr_reload_zone(zone_name_class)
         self._set_zone_refresh_timer(zone_name_class)
         self._set_zone_refresh_timer(zone_name_class)
         self._set_zone_state(zone_name_class, ZONE_OK)
         self._set_zone_state(zone_name_class, ZONE_OK)
-        self._set_zone_last_refresh_time(zone_name_class, self._get_current_time())
+        self._set_zone_last_refresh_time(zone_name_class,
+                                         self._get_current_time())
 
 
     def zone_refresh_fail(self, zone_name_class):
     def zone_refresh_fail(self, zone_name_class):
         """Update zone info after zone refresh fail"""
         """Update zone info after zone refresh fail"""
-        if (self._zone_not_exist(zone_name_class)):
-            logger.error(ZONEMGR_UNKNOWN_ZONE_FAIL, zone_name_class[0], zone_name_class[1])
+        if self._zone_not_exist(zone_name_class):
+            logger.error(ZONEMGR_UNKNOWN_ZONE_FAIL, zone_name_class[0],
+                         zone_name_class[1])
             raise ZonemgrException("[b10-zonemgr] Zone (%s, %s) doesn't "
             raise ZonemgrException("[b10-zonemgr] Zone (%s, %s) doesn't "
                                    "belong to zonemgr" % zone_name_class)
                                    "belong to zonemgr" % zone_name_class)
         # Is zone expired?
         # Is zone expired?
@@ -199,11 +215,6 @@ class ZonemgrRefresh:
         zone; the Auth module should have rejected the case where it's not
         zone; the Auth module should have rejected the case where it's not
         even authoritative for the zone.
         even authoritative for the zone.
 
 
-        Note: to be more robust and less independent from other module's
-        behavior, it's probably safer to check the authority condition here,
-        too.  But right now it uses SQLite3 specific API (to be deprecated),
-        so we rather rely on Auth.
-
         Parameters:
         Parameters:
         zone_name_class (Name, RRClass): the notified zone name and class.
         zone_name_class (Name, RRClass): the notified zone name and class.
         master (str): textual address of the NOTIFY sender.
         master (str): textual address of the NOTIFY sender.
@@ -219,35 +230,86 @@ class ZonemgrRefresh:
 
 
     def zonemgr_reload_zone(self, zone_name_class):
     def zonemgr_reload_zone(self, zone_name_class):
         """ Reload a zone."""
         """ Reload a zone."""
-        zone_soa = sqlite3_ds.get_zone_soa(str(zone_name_class[0]), self._db_file)
-        self._zonemgr_refresh_info[zone_name_class]["zone_soa_rdata"] = zone_soa[7]
+        self._zonemgr_refresh_info[zone_name_class]["zone_soa_rdata"] = \
+            self._get_zone_soa(zone_name_class)
 
 
     def zonemgr_add_zone(self, zone_name_class):
     def zonemgr_add_zone(self, zone_name_class):
         """ Add a zone into zone manager."""
         """ Add a zone into zone manager."""
-
-        logger.debug(DBG_ZONEMGR_BASIC, ZONEMGR_LOAD_ZONE, zone_name_class[0], zone_name_class[1])
+        logger.debug(DBG_ZONEMGR_BASIC, ZONEMGR_LOAD_ZONE, zone_name_class[0],
+                     zone_name_class[1])
         zone_info = {}
         zone_info = {}
-        zone_soa = sqlite3_ds.get_zone_soa(str(zone_name_class[0]), self._db_file)
+        zone_soa = self._get_zone_soa(zone_name_class)
         if zone_soa is None:
         if zone_soa is None:
             logger.warn(ZONEMGR_NO_SOA, zone_name_class[0], zone_name_class[1])
             logger.warn(ZONEMGR_NO_SOA, zone_name_class[0], zone_name_class[1])
             zone_info["zone_soa_rdata"] = None
             zone_info["zone_soa_rdata"] = None
             zone_reload_time = 0.0
             zone_reload_time = 0.0
         else:
         else:
-            zone_info["zone_soa_rdata"] = zone_soa[7]
-            zone_reload_time = float(zone_soa[7].split(" ")[RETRY_OFFSET])
+            zone_info["zone_soa_rdata"] = zone_soa
+            zone_reload_time = float(zone_soa.split(" ")[RETRY_OFFSET])
         zone_info["zone_state"] = ZONE_OK
         zone_info["zone_state"] = ZONE_OK
         zone_info["last_refresh_time"] = self._get_current_time()
         zone_info["last_refresh_time"] = self._get_current_time()
         self._zonemgr_refresh_info[zone_name_class] = zone_info
         self._zonemgr_refresh_info[zone_name_class] = zone_info
-        # Imposes some random jitters to avoid many zones need to do refresh at the same time.
+        # Imposes some random jitters to avoid many zones need to do refresh
+        # at the same time.
         zone_reload_time = max(self._lowerbound_retry, zone_reload_time)
         zone_reload_time = max(self._lowerbound_retry, zone_reload_time)
-        self._set_zone_timer(zone_name_class, zone_reload_time, self._reload_jitter * zone_reload_time)
+        self._set_zone_timer(zone_name_class, zone_reload_time,
+                             self._reload_jitter * zone_reload_time)
+
+    def _get_zone_soa(self, zone_name_class):
+        """Retrieve the current SOA RR of the zone to be transferred."""
+
+        def get_zone_soa_rrset(datasrc_client, zone_name, zone_class):
+            """Retrieve the current SOA RR of the zone to be transferred."""
+            # get the zone finder.  this must be SUCCESS (not even
+            # PARTIALMATCH) because we are specifying the zone origin name.
+            result, finder = datasrc_client.find_zone(zone_name)
+            if result != DataSourceClient.SUCCESS:
+                # The data source doesn't know the zone.  In the context in
+                # which this function is called, this shouldn't happen.
+                raise ZonemgrException(
+                    "unexpected result: zone %s/%s doesn't exist" %
+                    (zone_name.to_text(True), str(zone_class)))
+            result, soa_rrset, _ = finder.find(zone_name, RRType.SOA)
+            if result != ZoneFinder.SUCCESS:
+                logger.warn(ZONEMGR_NO_SOA,
+                            zone_name.to_text(True), str(zone_class))
+                return None
+            return soa_rrset
+
+        # Identify the data source to which the zone content is transferred,
+        # and get the current zone SOA from the data source (if available).
+        datasrc_client = None
+        clist = self._datasrc_clients_mgr.get_client_list(zone_name_class[1])
+        if clist is None:
+            return None
+        try:
+            datasrc_client = clist.find(zone_name_class[0], True, False)[0]
+            if datasrc_client is None: # can happen, so log it separately.
+                logger.error(ZONEMGR_DATASRC_UNKNOWN,
+                             zone_name_class[0] + '/' + zone_name_class[1])
+                return None
+            zone_soa = get_zone_soa_rrset(datasrc_client,
+                                          Name(zone_name_class[0]),
+                                          RRClass(zone_name_class[1]))
+            if zone_soa == None:
+                return None
+            else:
+                return zone_soa.get_rdata()[0].to_text()
+        except isc.datasrc.Error as ex:
+            # rare case error. re-raise as ZonemgrException so it'll be logged
+            # in command_handler().
+            raise ZonemgrException('unexpected failure in datasrc module: ' +
+                                   str(ex))
 
 
     def _zone_is_expired(self, zone_name_class):
     def _zone_is_expired(self, zone_name_class):
         """Judge whether a zone is expired or not."""
         """Judge whether a zone is expired or not."""
-        zone_expired_time = float(self._get_zone_soa_rdata(zone_name_class).split(" ")[EXPIRED_OFFSET])
-        zone_last_refresh_time = self._get_zone_last_refresh_time(zone_name_class)
+        zone_expired_time = float(self._get_zone_soa_rdata(zone_name_class).
+                                      split(" ")[EXPIRED_OFFSET])
+        zone_last_refresh_time = \
+            self._get_zone_last_refresh_time(zone_name_class)
         if (ZONE_EXPIRED == self._get_zone_state(zone_name_class) or
         if (ZONE_EXPIRED == self._get_zone_state(zone_name_class) or
-            zone_last_refresh_time + zone_expired_time <= self._get_current_time()):
+            zone_last_refresh_time + zone_expired_time <=
+                self._get_current_time()):
             return True
             return True
 
 
         return False
         return False
@@ -262,16 +324,19 @@ class ZonemgrRefresh:
         self._zonemgr_refresh_info[zone_name_class]["last_refresh_time"] = time
         self._zonemgr_refresh_info[zone_name_class]["last_refresh_time"] = time
 
 
     def _get_zone_notifier_master(self, zone_name_class):
     def _get_zone_notifier_master(self, zone_name_class):
-        if ("notify_master" in self._zonemgr_refresh_info[zone_name_class].keys()):
+        if ("notify_master" in
+                self._zonemgr_refresh_info[zone_name_class].keys()):
             return self._zonemgr_refresh_info[zone_name_class]["notify_master"]
             return self._zonemgr_refresh_info[zone_name_class]["notify_master"]
 
 
         return None
         return None
 
 
     def _set_zone_notifier_master(self, zone_name_class, master_addr):
     def _set_zone_notifier_master(self, zone_name_class, master_addr):
-        self._zonemgr_refresh_info[zone_name_class]["notify_master"] = master_addr
+        self._zonemgr_refresh_info[zone_name_class]["notify_master"] = \
+            master_addr
 
 
     def _clear_zone_notifier_master(self, zone_name_class):
     def _clear_zone_notifier_master(self, zone_name_class):
-        if ("notify_master" in self._zonemgr_refresh_info[zone_name_class].keys()):
+        if ("notify_master" in
+                self._zonemgr_refresh_info[zone_name_class].keys()):
             del self._zonemgr_refresh_info[zone_name_class]["notify_master"]
             del self._zonemgr_refresh_info[zone_name_class]["notify_master"]
 
 
     def _get_zone_state(self, zone_name_class):
     def _get_zone_state(self, zone_name_class):
@@ -295,7 +360,7 @@ class ZonemgrRefresh:
     def _send_command(self, module_name, command_name, params):
     def _send_command(self, module_name, command_name, params):
         """Send command between modules."""
         """Send command between modules."""
         try:
         try:
-            self._mccs.rpc_call(command_name, module_name, params=params)
+            self._module_cc.rpc_call(command_name, module_name, params=params)
         except socket.error:
         except socket.error:
             # FIXME: WTF? Where does socket.error come from? And how do we ever
             # FIXME: WTF? Where does socket.error come from? And how do we ever
             # dare ignore such serious error? It can only be broken link to
             # dare ignore such serious error? It can only be broken link to
@@ -314,7 +379,8 @@ class ZonemgrRefresh:
             # If hasn't received refresh response but are within refresh
             # If hasn't received refresh response but are within refresh
             # timeout, skip the zone
             # timeout, skip the zone
             if (ZONE_REFRESHING == zone_state and
             if (ZONE_REFRESHING == zone_state and
-                (self._get_zone_refresh_timeout(zone_name_class) > self._get_current_time())):
+                (self._get_zone_refresh_timeout(zone_name_class) >
+                     self._get_current_time())):
                 continue
                 continue
 
 
             # Get the zone with minimum next_refresh_time
             # Get the zone with minimum next_refresh_time
@@ -324,7 +390,8 @@ class ZonemgrRefresh:
                 zone_need_refresh = zone_name_class
                 zone_need_refresh = zone_name_class
 
 
             # Find the zone need do refresh
             # Find the zone need do refresh
-            if (self._get_zone_next_refresh_time(zone_need_refresh) < self._get_current_time()):
+            if (self._get_zone_next_refresh_time(zone_need_refresh) <
+                    self._get_current_time()):
                 break
                 break
 
 
         return zone_need_refresh
         return zone_need_refresh
@@ -332,9 +399,12 @@ class ZonemgrRefresh:
 
 
     def _do_refresh(self, zone_name_class):
     def _do_refresh(self, zone_name_class):
         """Do zone refresh."""
         """Do zone refresh."""
-        logger.debug(DBG_ZONEMGR_BASIC, ZONEMGR_REFRESH_ZONE, zone_name_class[0], zone_name_class[1])
+        logger.debug(DBG_ZONEMGR_BASIC, ZONEMGR_REFRESH_ZONE,
+                     zone_name_class[0], zone_name_class[1])
         self._set_zone_state(zone_name_class, ZONE_REFRESHING)
         self._set_zone_state(zone_name_class, ZONE_REFRESHING)
-        self._set_zone_refresh_timeout(zone_name_class, self._get_current_time() + self._max_transfer_timeout)
+        self._set_zone_refresh_timeout(zone_name_class,
+                                       self._get_current_time() +
+                                           self._max_transfer_timeout)
         notify_master = self._get_zone_notifier_master(zone_name_class)
         notify_master = self._get_zone_notifier_master(zone_name_class)
         # If the zone has notify master, send notify command to xfrin module
         # If the zone has notify master, send notify command to xfrin module
         if notify_master:
         if notify_master:
@@ -351,13 +421,6 @@ class ZonemgrRefresh:
                     }
                     }
             self._send_command(XFRIN_MODULE_NAME, ZONE_REFRESH_COMMAND, param)
             self._send_command(XFRIN_MODULE_NAME, ZONE_REFRESH_COMMAND, param)
 
 
-    def _zone_mgr_is_empty(self):
-        """Does zone manager has no zone?"""
-        if not len(self._zonemgr_refresh_info):
-            return True
-
-        return False
-
     def _run_timer(self, start_event):
     def _run_timer(self, start_event):
         while self._running:
         while self._running:
             # Notify run_timer that we already started and are inside the loop.
             # Notify run_timer that we already started and are inside the loop.
@@ -367,24 +430,29 @@ class ZonemgrRefresh:
             if start_event:
             if start_event:
                 start_event.set()
                 start_event.set()
                 start_event = None
                 start_event = None
-            # If zonemgr has no zone, set timer timeout to self._lowerbound_retry.
-            if self._zone_mgr_is_empty():
+            # If zonemgr has no zone, set timeout to minimum
+            if not self._zonemgr_refresh_info:
                 timeout = self._lowerbound_retry
                 timeout = self._lowerbound_retry
             else:
             else:
                 zone_need_refresh = self._find_need_do_refresh_zone()
                 zone_need_refresh = self._find_need_do_refresh_zone()
-                # If don't get zone with minimum next refresh time, set timer timeout to self._lowerbound_retry.
+                # If don't get zone with minimum next refresh time, set
+                # timeout to minimum
                 if not zone_need_refresh:
                 if not zone_need_refresh:
                     timeout = self._lowerbound_retry
                     timeout = self._lowerbound_retry
                 else:
                 else:
-                    timeout = self._get_zone_next_refresh_time(zone_need_refresh) - self._get_current_time()
-                    if (timeout < 0):
+                    timeout = \
+                        self._get_zone_next_refresh_time(zone_need_refresh) - \
+                        self._get_current_time()
+                    if timeout < 0:
                         self._do_refresh(zone_need_refresh)
                         self._do_refresh(zone_need_refresh)
                         continue
                         continue
 
 
             """ Wait for the socket notification for a maximum time of timeout
             """ Wait for the socket notification for a maximum time of timeout
             in seconds (as float)."""
             in seconds (as float)."""
             try:
             try:
-                rlist, wlist, xlist = select.select([self._check_sock, self._read_sock], [], [], timeout)
+                rlist, wlist, xlist = \
+                    select.select([self._check_sock, self._read_sock],
+                                  [], [], timeout)
             except select.error as e:
             except select.error as e:
                 if e.args[0] == errno.EINTR:
                 if e.args[0] == errno.EINTR:
                     (rlist, wlist, xlist) = ([], [], [])
                     (rlist, wlist, xlist) = ([], [], [])
@@ -403,8 +471,8 @@ class ZonemgrRefresh:
 
 
     def run_timer(self, daemon=False):
     def run_timer(self, daemon=False):
         """
         """
-        Keep track of zone timers. Spawns and starts a thread. The thread object
-        is returned.
+        Keep track of zone timers. Spawns and starts a thread. The thread
+        object is returned.
 
 
         You can stop it by calling shutdown().
         You can stop it by calling shutdown().
         """
         """
@@ -429,6 +497,20 @@ class ZonemgrRefresh:
         # Return the thread to anyone interested
         # Return the thread to anyone interested
         return self._thread
         return self._thread
 
 
+    def _datasrc_config_handler(self, new_config, config_data):
+        """Configuration handler of the 'data_sources' module.
+
+        The actual handling is delegated to the DataSrcClientsMgr class;
+        this method is a simple wrapper.
+
+        This is essentially private, but implemented as 'protected' so tests
+        can refer to it; other external use is prohibited.
+        """
+        try:
+            self._datasrc_clients_mgr.reconfigure(new_config, config_data)
+        except isc.server_common.datasrc_clients_mgr.ConfigError as ex:
+            logger.error(ZONEMGR_DATASRC_CONFIG_ERROR, ex)
+
     def shutdown(self):
     def shutdown(self):
         """
         """
         Stop the run_timer() thread. Block until it finished. This must be
         Stop the run_timer() thread. Block until it finished. This must be
@@ -450,7 +532,7 @@ class ZonemgrRefresh:
         self._read_sock = None
         self._read_sock = None
         self._write_sock = None
         self._write_sock = None
 
 
-    def update_config_data(self, new_config, module_cc_session):
+    def update_config_data(self, new_config, module_cc):
         """ update ZonemgrRefresh config """
         """ update ZonemgrRefresh config """
         # Get a new value, but only if it is defined (commonly used below)
         # Get a new value, but only if it is defined (commonly used below)
         # We don't use "value or default", because if value would be
         # We don't use "value or default", because if value would be
@@ -499,7 +581,7 @@ class ZonemgrRefresh:
                     # Currently we use an explicit get_default_value call
                     # Currently we use an explicit get_default_value call
                     # in case the class hasn't been set. Alternatively, we
                     # in case the class hasn't been set. Alternatively, we
                     # could use
                     # could use
-                    # module_cc_session.get_value('secondary_zones[INDEX]/class')
+                    # module_cc.get_value('secondary_zones[INDEX]/class')
                     # To get either the value that was set, or the default if
                     # To get either the value that was set, or the default if
                     # it wasn't set.
                     # it wasn't set.
                     # But the real solution would be to make new_config a type
                     # But the real solution would be to make new_config a type
@@ -509,7 +591,7 @@ class ZonemgrRefresh:
                     if 'class' in secondary_zone:
                     if 'class' in secondary_zone:
                         rr_class = secondary_zone['class']
                         rr_class = secondary_zone['class']
                     else:
                     else:
-                        rr_class = module_cc_session.get_default_value(
+                        rr_class = module_cc.get_default_value(
                                         'secondary_zones/class')
                                         'secondary_zones/class')
                     # Convert rr_class to and from RRClass to check its value
                     # Convert rr_class to and from RRClass to check its value
                     try:
                     try:
@@ -521,10 +603,12 @@ class ZonemgrRefresh:
                     required[name_class] = True
                     required[name_class] = True
                     # Add it only if it isn't there already
                     # Add it only if it isn't there already
                     if not name_class in self._zonemgr_refresh_info:
                     if not name_class in self._zonemgr_refresh_info:
-                        # If we are not able to find it in database, log an warning
+                        # If we are not able to find it in database, log an
+                        # warning
                         self.zonemgr_add_zone(name_class)
                         self.zonemgr_add_zone(name_class)
                 # Drop the zones that are no longer there
                 # Drop the zones that are no longer there
-                # Do it in two phases, python doesn't like deleting while iterating
+                # Do it in two phases, python doesn't like deleting while
+                # iterating
                 to_drop = []
                 to_drop = []
                 for old_zone in self._zonemgr_refresh_info:
                 for old_zone in self._zonemgr_refresh_info:
                     if not old_zone in required:
                     if not old_zone in required:
@@ -539,10 +623,11 @@ class Zonemgr:
     def __init__(self):
     def __init__(self):
         self._zone_refresh = None
         self._zone_refresh = None
         self._setup_session()
         self._setup_session()
-        self._db_file = self.get_db_file()
-        # Create socket pair for communicating between main thread and zonemgr timer thread
-        self._master_socket, self._slave_socket = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
-        self._zone_refresh = ZonemgrRefresh(self._db_file, self._slave_socket, self._module_cc)
+        # Create socket pair for communicating between main thread and zonemgr
+        # timer thread
+        self._master_socket, self._slave_socket = \
+            socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
+        self._zone_refresh = ZonemgrRefresh(self._slave_socket, self._module_cc)
         self._zone_refresh.run_timer()
         self._zone_refresh.run_timer()
 
 
         self._lock = threading.Lock()
         self._lock = threading.Lock()
@@ -550,9 +635,10 @@ class Zonemgr:
         self.running = False
         self.running = False
 
 
     def _setup_session(self):
     def _setup_session(self):
-        """Setup two sessions for zonemgr, one(self._module_cc) is used for receiving
-        commands and config data sent from other modules, another one (self._cc)
-        is used to send commands to proper modules."""
+        """Setup two sessions for zonemgr, one(self._module_cc) is used for
+        receiving commands and config data sent from other modules, another
+        one (self._cc) is used to send commands to proper modules.
+        """
         self._module_cc = isc.config.ModuleCCSession(SPECFILE_LOCATION,
         self._module_cc = isc.config.ModuleCCSession(SPECFILE_LOCATION,
                                                   self.config_handler,
                                                   self.config_handler,
                                                   self.command_handler)
                                                   self.command_handler)
@@ -561,18 +647,9 @@ class Zonemgr:
         self._config_data_check(self._config_data)
         self._config_data_check(self._config_data)
         self._module_cc.start()
         self._module_cc.start()
 
 
-    def get_db_file(self):
-        db_file, is_default = self._module_cc.get_remote_config_value(AUTH_MODULE_NAME, "database_file")
-        # this too should be unnecessary, but currently the
-        # 'from build' override isn't stored in the config
-        # (and we don't have indirect python access to datasources yet)
-        if is_default and "B10_FROM_BUILD" in os.environ:
-            db_file = os.environ["B10_FROM_BUILD"] + "/bind10_zones.sqlite3"
-        return db_file
-
     def shutdown(self):
     def shutdown(self):
         """Shutdown the zonemgr process. The thread which is keeping track of
         """Shutdown the zonemgr process. The thread which is keeping track of
-           zone timers should be terminated.
+        zone timers should be terminated.
         """
         """
         self._zone_refresh.shutdown()
         self._zone_refresh.shutdown()
 
 
@@ -596,7 +673,8 @@ class Zonemgr:
         self._config_data_check(complete)
         self._config_data_check(complete)
         if self._zone_refresh is not None:
         if self._zone_refresh is not None:
             try:
             try:
-                self._zone_refresh.update_config_data(complete, self._module_cc)
+                self._zone_refresh.update_config_data(complete,
+                                                      self._module_cc)
             except Exception as e:
             except Exception as e:
                 answer = create_answer(1, str(e))
                 answer = create_answer(1, str(e))
                 ok = False
                 ok = False
@@ -608,7 +686,8 @@ class Zonemgr:
     def _config_data_check(self, config_data):
     def _config_data_check(self, config_data):
         """Check whether the new config data is valid or
         """Check whether the new config data is valid or
         not. It contains only basic logic, not full check against
         not. It contains only basic logic, not full check against
-        database."""
+        database.
+        """
         # jitter should not be bigger than half of the original value
         # jitter should not be bigger than half of the original value
         if config_data.get('refresh_jitter') > 0.5:
         if config_data.get('refresh_jitter') > 0.5:
             config_data['refresh_jitter'] = 0.5
             config_data['refresh_jitter'] = 0.5
@@ -625,7 +704,7 @@ class Zonemgr:
             logger.error(ZONEMGR_NO_ZONE_CLASS)
             logger.error(ZONEMGR_NO_ZONE_CLASS)
             raise ZonemgrException("zone class should be provided")
             raise ZonemgrException("zone class should be provided")
 
 
-        if (command != ZONE_NOTIFY_COMMAND):
+        if command != ZONE_NOTIFY_COMMAND:
             return (zone_name, zone_class)
             return (zone_name, zone_class)
 
 
         master_str = args.get("master")
         master_str = args.get("master")
@@ -641,7 +720,8 @@ class Zonemgr:
         ZONE_NOTIFY_COMMAND is issued by Auth process;
         ZONE_NOTIFY_COMMAND is issued by Auth process;
         ZONE_NEW_DATA_READY_CMD and ZONE_XFRIN_FAILED are issued by
         ZONE_NEW_DATA_READY_CMD and ZONE_XFRIN_FAILED are issued by
         Xfrin process;
         Xfrin process;
-        shutdown is issued by a user or Init process. """
+        shutdown is issued by a user or Init process.
+        """
         answer = create_answer(0)
         answer = create_answer(0)
         if command == ZONE_NOTIFY_COMMAND:
         if command == ZONE_NOTIFY_COMMAND:
             """ Handle Auth notify command"""
             """ Handle Auth notify command"""

+ 11 - 1
src/bin/zonemgr/zonemgr_messages.mes

@@ -1,4 +1,4 @@
-# Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2011-2013  Internet Systems Consortium, Inc. ("ISC")
 #
 #
 # Permission to use, copy, modify, and/or distribute this software for any
 # Permission to use, copy, modify, and/or distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
 # purpose with or without fee is hereby granted, provided that the above
@@ -19,6 +19,16 @@
 An error was encountered on the command channel.  The message indicates
 An error was encountered on the command channel.  The message indicates
 the nature of the error.
 the nature of the error.
 
 
+% ZONEMGR_DATASRC_CONFIG_ERROR failed to update data source configuration: %1
+Configuration for the global data sources is updated, but the update
+cannot be applied to zonemgr.  The zonemgr module will still keep running
+with the previous configuration, but the cause of the failure and
+other log messages must be carefully examined because if only zonemgr
+rejects the new configuration then the entire BIND 10 system will have
+inconsistent state among different modules.  If other modules accept
+the update but zonemgr produces this error, the zonemgr module should
+probably be restarted.
+
 % ZONEMGR_JITTER_TOO_BIG refresh_jitter is too big, setting to 0.5
 % ZONEMGR_JITTER_TOO_BIG refresh_jitter is too big, setting to 0.5
 The value specified in the configuration for the refresh jitter is too large
 The value specified in the configuration for the refresh jitter is too large
 so its value has been set to the maximum of 0.5.
 so its value has been set to the maximum of 0.5.

+ 0 - 1
tests/lettuce/configurations/xfrin/retransfer_slave.conf.orig

@@ -8,7 +8,6 @@
         } ]
         } ]
     },
     },
     "Auth": {
     "Auth": {
-        "database_file": "data/test_nonexistent_db.sqlite3",
         "listen_on": [ {
         "listen_on": [ {
             "address": "::1",
             "address": "::1",
             "port": 47806
             "port": 47806

+ 0 - 1
tests/lettuce/configurations/xfrin/retransfer_slave_diffs.conf

@@ -8,7 +8,6 @@
         } ]
         } ]
     },
     },
     "Auth": {
     "Auth": {
-        "database_file": "data/xfrin-before-diffs.sqlite3",
         "listen_on": [ {
         "listen_on": [ {
             "address": "::1",
             "address": "::1",
             "port": 47806
             "port": 47806

+ 0 - 1
tests/lettuce/configurations/xfrin/retransfer_slave_notify.conf.orig

@@ -8,7 +8,6 @@
         } ]
         } ]
     },
     },
     "Auth": {
     "Auth": {
-        "database_file": "data/xfrin-notify.sqlite3",
         "listen_on": [ {
         "listen_on": [ {
             "address": "::1",
             "address": "::1",
             "port": 47806
             "port": 47806

+ 0 - 1
tests/lettuce/configurations/xfrin/retransfer_slave_notify_v4.conf

@@ -8,7 +8,6 @@
         } ]
         } ]
     },
     },
     "Auth": {
     "Auth": {
-        "database_file": "data/xfrin-notify.sqlite3",
         "listen_on": [ {
         "listen_on": [ {
             "address": "127.0.0.1",
             "address": "127.0.0.1",
             "port": 47806
             "port": 47806