[svn] commit: r2736 - in /trunk: ./ src/bin/ src/bin/auth/ src/bin/bind10/ src/bin/xfrin/ src/bin/xfrin/tests/ src/bin/xfrout/ src/bin/zonemgr/ src/lib/cc/ src/lib/cc/tests/ src/lib/datasrc/ src/lib/dns/ src/lib/dns/rdata/generic/ src/lib/dns/tests/ src/lib/dns/util/ src/lib/exceptions/tests/ src/lib/python/isc/ src/lib/python/isc/datasrc/ src/lib/python/isc/notify/ src/lib/python/isc/notify/tests/

BIND 10 source code commits bind10-changes at lists.isc.org
Mon Aug 16 09:05:53 UTC 2010


Author: chenzhengzhang
Date: Mon Aug 16 09:05:52 2010
New Revision: 2736

Log:
merge trac215(zone manager) and trac289(notify-out)


Added:
    trunk/src/bin/zonemgr/
      - copied from r2733, branches/trac289/src/bin/zonemgr/
    trunk/src/lib/python/isc/notify/
      - copied from r2733, branches/trac289/src/lib/python/isc/notify/
Modified:
    trunk/   (props changed)
    trunk/ChangeLog
    trunk/configure.ac
    trunk/src/bin/Makefile.am
    trunk/src/bin/auth/auth_srv.cc
    trunk/src/bin/bind10/bind10.py.in
    trunk/src/bin/bind10/run_bind10.sh.in
    trunk/src/bin/xfrin/   (props changed)
    trunk/src/bin/xfrin/tests/xfrin_test.py
    trunk/src/bin/xfrin/xfrin.py.in
    trunk/src/bin/xfrin/xfrin.spec.pre.in
    trunk/src/bin/xfrout/xfrout.py.in
    trunk/src/lib/cc/   (props changed)
    trunk/src/lib/cc/tests/   (props changed)
    trunk/src/lib/datasrc/   (props changed)
    trunk/src/lib/dns/   (props changed)
    trunk/src/lib/dns/rdata/generic/rrsig_46.cc   (props changed)
    trunk/src/lib/dns/tests/   (props changed)
    trunk/src/lib/dns/util/   (props changed)
    trunk/src/lib/exceptions/tests/   (props changed)
    trunk/src/lib/python/isc/Makefile.am
    trunk/src/lib/python/isc/datasrc/sqlite3_ds.py
    trunk/src/lib/python/isc/notify/tests/notify_out_test.py

Modified: trunk/ChangeLog
==============================================================================
--- trunk/ChangeLog (original)
+++ trunk/ChangeLog Mon Aug 16 09:05:52 2010
@@ -1,3 +1,14 @@
+  87.   [func]      zhanglikun
+	lib/python/isc/notifyout: Add the feature of notify-out, when 
+	zone axfr/ixfr finishing, the server will notify its slaves.
+	(Trac #289, svn r2735)
+
+  86.   [func]      jerry
+    bin/zonemgr: Added zone manager module. The zone manager is	one 
+	of the co-operating processes of BIND10, which keeps track of 
+	timers and other information necessary for BIND10 to act as a 
+	slave. (Trac #215, svn r2735)
+
   85.	[build]*	jinmei
 	Build programs using dynamic link by default.  A new configure
 	option --enable-static-link is provided to force static link for

Modified: trunk/configure.ac
==============================================================================
--- trunk/configure.ac (original)
+++ trunk/configure.ac Mon Aug 16 09:05:52 2010
@@ -411,6 +411,8 @@
                  src/bin/xfrin/tests/Makefile
                  src/bin/xfrout/Makefile
                  src/bin/xfrout/tests/Makefile
+                 src/bin/zonemgr/Makefile
+                 src/bin/zonemgr/tests/Makefile
                  src/bin/usermgr/Makefile
                  src/lib/Makefile
                  src/lib/bench/Makefile
@@ -427,6 +429,8 @@
                  src/lib/python/isc/config/tests/Makefile
                  src/lib/python/isc/log/Makefile
                  src/lib/python/isc/log/tests/Makefile
+                 src/lib/python/isc/notify/Makefile
+                 src/lib/python/isc/notify/tests/Makefile
                  src/lib/config/Makefile
                  src/lib/config/tests/Makefile
                  src/lib/dns/Makefile
@@ -453,6 +457,10 @@
            src/bin/xfrout/xfrout.spec.pre
            src/bin/xfrout/tests/xfrout_test
            src/bin/xfrout/run_b10-xfrout.sh
+           src/bin/zonemgr/zonemgr.py
+           src/bin/zonemgr/zonemgr.spec.pre
+           src/bin/zonemgr/tests/zonemgr_test
+           src/bin/zonemgr/run_b10-zonemgr.sh
            src/bin/bind10/bind10.py
            src/bin/bind10/tests/bind10_test
            src/bin/bind10/run_bind10.sh
@@ -474,6 +482,7 @@
            src/lib/python/isc/config/tests/config_test
            src/lib/python/isc/cc/tests/cc_test
            src/lib/python/isc/log/tests/log_test
+           src/lib/python/isc/notify/tests/notify_out_test
            src/lib/dns/gen-rdatacode.py
            src/lib/python/bind10_config.py
            src/lib/dns/tests/testdata/gen-wiredata.py
@@ -482,10 +491,12 @@
            chmod +x src/bin/cmdctl/run_b10-cmdctl.sh
            chmod +x src/bin/xfrin/run_b10-xfrin.sh
            chmod +x src/bin/xfrout/run_b10-xfrout.sh
+           chmod +x src/bin/zonemgr/run_b10-zonemgr.sh
            chmod +x src/bin/bind10/run_bind10.sh
            chmod +x src/bin/cmdctl/tests/cmdctl_test
            chmod +x src/bin/xfrin/tests/xfrin_test
            chmod +x src/bin/xfrout/tests/xfrout_test
+           chmod +x src/bin/zonemgr/tests/zonemgr_test
            chmod +x src/bin/bindctl/tests/bindctl_test
            chmod +x src/bin/bindctl/run_bindctl.sh
            chmod +x src/bin/loadzone/run_loadzone.sh

Modified: trunk/src/bin/Makefile.am
==============================================================================
--- trunk/src/bin/Makefile.am (original)
+++ trunk/src/bin/Makefile.am Mon Aug 16 09:05:52 2010
@@ -1,1 +1,1 @@
-SUBDIRS = bind10 bindctl cfgmgr loadzone msgq host cmdctl auth xfrin xfrout usermgr
+SUBDIRS = bind10 bindctl cfgmgr loadzone msgq host cmdctl auth xfrin xfrout usermgr zonemgr

Modified: trunk/src/bin/auth/auth_srv.cc
==============================================================================
--- trunk/src/bin/auth/auth_srv.cc (original)
+++ trunk/src/bin/auth/auth_srv.cc Mon Aug 16 09:05:52 2010
@@ -326,7 +326,6 @@
 
     return (true);
 }
-
 
 bool
 AuthSrvImpl::processAxfrQuery(const IOMessage& io_message, Message& message,
@@ -423,7 +422,7 @@
     static const string command_template_start =
         "{\"command\": [\"notify\", {\"zone_name\" : \"";
     static const string command_template_master = "\", \"master\" : \"";
-    static const string command_template_rrclass = "\", \"rrclass\" : \"";
+    static const string command_template_rrclass = "\", \"zone_class\" : \"";
     static const string command_template_end = "\"}]}";
 
     try {
@@ -433,7 +432,7 @@
                 command_template_rrclass + question->getClass().toText() +
                 command_template_end);
         const unsigned int seq =
-            xfrin_session_->group_sendmsg(notify_command, "Xfrin",
+            xfrin_session_->group_sendmsg(notify_command, "Zonemgr",
                                           "*", "*");
         ElementPtr env, answer, parsed_answer;
         xfrin_session_->group_recvmsg(env, answer, false, seq);
@@ -441,14 +440,14 @@
         parsed_answer = parseAnswer(rcode, answer);
         if (rcode != 0) {
             if (verbose_mode_) {
-                cerr << "[b10-auth] failed to notify Xfrin: "
+                cerr << "[b10-auth] failed to notify Zonemgr: "
                      << parsed_answer->str() << endl; 
             }
             return (false);
         }
     } catch (const Exception& ex) {
         if (verbose_mode_) {
-            cerr << "[b10-auth] failed to notify Xfrin: " << ex.what() << endl;
+            cerr << "[b10-auth] failed to notify Zonemgr: " << ex.what() << endl;
         }
         return (false);
     }

Modified: trunk/src/bin/bind10/bind10.py.in
==============================================================================
--- trunk/src/bin/bind10/bind10.py.in (original)
+++ trunk/src/bin/bind10/bind10.py.in Mon Aug 16 09:05:52 2010
@@ -398,6 +398,26 @@
             sys.stdout.write("[bind10] Started b10-xfrin (PID %d)\n" % 
                              xfrind.pid)
 
+        # start b10-zonemgr
+        zonemgr_args = ['b10-zonemgr']
+        if self.verbose:
+            sys.stdout.write("[bind10] Starting b10-zonemgr\n")
+            zonemgr_args += ['-v']
+        try:
+            zonemgr = ProcessInfo("b10-zonemgr", zonemgr_args,
+                                 c_channel_env)
+        except Exception as e:
+            c_channel.process.kill()
+            bind_cfgd.process.kill()
+            xfrout.process.kill()
+            auth.process.kill()
+            xfrind.process.kill()
+            return "Unable to start b10-zonemgr; " + str(e)
+        self.processes[zonemgr.pid] = zonemgr 
+        if self.verbose:
+            sys.stdout.write("[bind10] Started b10-zonemgr(PID %d)\n" % 
+                             zonemgr.pid)
+
         # start the b10-cmdctl
         # XXX: we hardcode port 8080
         cmdctl_args = ['b10-cmdctl']
@@ -413,6 +433,7 @@
             xfrout.process.kill()
             auth.process.kill()
             xfrind.process.kill()
+            zonemgr.process.kill()
             return "Unable to start b10-cmdctl; " + str(e)
         self.processes[cmd_ctrld.pid] = cmd_ctrld
         if self.verbose:
@@ -431,6 +452,7 @@
         self.cc_session.group_sendmsg(cmd, "Boss", "Auth")
         self.cc_session.group_sendmsg(cmd, "Boss", "Xfrout")
         self.cc_session.group_sendmsg(cmd, "Boss", "Xfrin")
+        self.cc_session.group_sendmsg(cmd, "Boss", "Zonemgr")
 
     def stop_process(self, process):
         """Stop the given process, friendly-like."""

Modified: trunk/src/bin/bind10/run_bind10.sh.in
==============================================================================
--- trunk/src/bin/bind10/run_bind10.sh.in (original)
+++ trunk/src/bin/bind10/run_bind10.sh.in Mon Aug 16 09:05:52 2010
@@ -20,7 +20,7 @@
 
 BIND10_PATH=@abs_top_builddir@/src/bin/bind10
 
-PATH=@abs_top_builddir@/src/bin/msgq:@abs_top_builddir@/src/bin/auth:@abs_top_builddir@/src/bin/cfgmgr:@abs_top_builddir@/src/bin/cmdctl:@abs_top_builddir@/src/bin/xfrin:@abs_top_builddir@/src/bin/xfrout:$PATH
+PATH=@abs_top_builddir@/src/bin/msgq:@abs_top_builddir@/src/bin/auth:@abs_top_builddir@/src/bin/cfgmgr:@abs_top_builddir@/src/bin/cmdctl:@abs_top_builddir@/src/bin/xfrin:@abs_top_builddir@/src/bin/xfrout:@abs_top_builddir@/src/bin/zonemgr:$PATH
 export PATH
 
 PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/lib/dns/python/.libs:@abs_top_builddir@/src/lib/xfr/.libs

Modified: trunk/src/bin/xfrin/tests/xfrin_test.py
==============================================================================
--- trunk/src/bin/xfrin/tests/xfrin_test.py (original)
+++ trunk/src/bin/xfrin/tests/xfrin_test.py Mon Aug 16 09:05:52 2010
@@ -63,6 +63,9 @@
 
     def _cc_setup(self):
         pass
+
+    def _get_db_file(self):
+        pass
     
     def _cc_check_command(self):
         self._shutdown_event.set()
@@ -408,11 +411,16 @@
     def tearDown(self):
         self.xfr.shutdown()
 
-    def _do_parse(self):
-        return self.xfr._parse_cmd_params(self.args)
+    def _do_parse_zone_name_class(self):
+        return self.xfr._parse_zone_name_and_class(self.args)
+
+    def _do_parse_master_port(self):
+        return self.xfr._parse_master_and_port(self.args)
 
     def test_parse_cmd_params(self):
-        name, rrclass, master_addrinfo, db_file = self._do_parse()
+        name, rrclass = self._do_parse_zone_name_class()
+        master_addrinfo = self._do_parse_master_port()
+        db_file = self.args.get('db_file')
         self.assertEqual(master_addrinfo[4][1], int(TEST_MASTER_PORT))
         self.assertEqual(name, TEST_ZONE_NAME)
         self.assertEqual(rrclass, TEST_RRCLASS)
@@ -421,49 +429,50 @@
 
     def test_parse_cmd_params_default_port(self):
         del self.args['port']
-        master_addrinfo = self._do_parse()[2]
+        master_addrinfo = self._do_parse_master_port()
         self.assertEqual(master_addrinfo[4][1], 53)
 
     def test_parse_cmd_params_ip6master(self):
         self.args['master'] = TEST_MASTER_IPV6_ADDRESS
-        master_addrinfo = self._do_parse()[2]
+        master_addrinfo = self._do_parse_master_port()
         self.assertEqual(master_addrinfo[4][0], TEST_MASTER_IPV6_ADDRESS)
 
     def test_parse_cmd_params_chclass(self):
-        self.args['rrclass'] = 'CH'
-        self.assertEqual(self._do_parse()[1], RRClass.CH())
+        self.args['zone_class'] = 'CH'
+        self.assertEqual(self._do_parse_zone_name_class()[1], RRClass.CH())
 
     def test_parse_cmd_params_bogusclass(self):
-        self.args['rrclass'] = 'XXX'
-        self.assertRaises(XfrinException, self._do_parse)
+        self.args['zone_class'] = 'XXX'
+        self.assertRaises(XfrinException, self._do_parse_zone_name_class)
 
     def test_parse_cmd_params_nozone(self):
         # zone name is mandatory.
         del self.args['zone_name']
-        self.assertRaises(XfrinException, self._do_parse)
+        self.assertRaises(XfrinException, self._do_parse_zone_name_class)
 
     def test_parse_cmd_params_nomaster(self):
         # master address is mandatory.
         del self.args['master']
-        self.assertRaises(XfrinException, self._do_parse)
+        master_addrinfo = self._do_parse_master_port()
+        self.assertEqual(master_addrinfo[4][0], DEFAULT_MASTER)
 
     def test_parse_cmd_params_bad_ip4(self):
         self.args['master'] = '3.3.3.3.3'
-        self.assertRaises(XfrinException, self._do_parse)
+        self.assertRaises(XfrinException, self._do_parse_master_port)
 
     def test_parse_cmd_params_bad_ip6(self):
         self.args['master'] = '1::1::1'
-        self.assertRaises(XfrinException, self._do_parse)
+        self.assertRaises(XfrinException, self._do_parse_master_port)
 
     def test_parse_cmd_params_bad_port(self):
         self.args['port'] = '-1'
-        self.assertRaises(XfrinException, self._do_parse)
+        self.assertRaises(XfrinException, self._do_parse_master_port)
 
         self.args['port'] = '65536'
-        self.assertRaises(XfrinException, self._do_parse)
+        self.assertRaises(XfrinException, self._do_parse_master_port)
 
         self.args['port'] = 'http'
-        self.assertRaises(XfrinException, self._do_parse)
+        self.assertRaises(XfrinException, self._do_parse_master_port)
 
     def test_command_handler_shutdown(self):
         self.assertEqual(self.xfr.command_handler("shutdown",
@@ -518,10 +527,31 @@
         self.args['master'] = TEST_MASTER_IPV6_ADDRESS
         # ...but right now we disable the feature due to security concerns.
         self.assertEqual(self.xfr.command_handler("notify",
-                                                  self.args)['result'][0], 1)
+                                                  self.args)['result'][0], 0)
 
     def test_command_handler_unknown(self):
         self.assertEqual(self.xfr.command_handler("xxx", None)['result'][0], 1)
+
+    def test_command_handler_transfers_in(self):
+        self.assertEqual(self.xfr.config_handler({})['result'][0], 0)
+        self.assertEqual(self.xfr.config_handler({'transfers_in': 3})['result'][0], 0)
+        self.assertEqual(self.xfr._max_transfers_in, 3)
+
+    def test_command_handler_masters(self):
+        master_info = {'master_addr': '1.1.1.1', 'master_port':53}
+        self.assertEqual(self.xfr.config_handler(master_info)['result'][0], 0)
+
+        master_info = {'master_addr': '1111.1.1.1', 'master_port':53 }
+        self.assertEqual(self.xfr.config_handler(master_info)['result'][0], 1)
+
+        master_info = {'master_addr': '2.2.2.2', 'master_port':530000 }
+        self.assertEqual(self.xfr.config_handler(master_info)['result'][0], 1)
+
+        master_info = {'master_addr': '2.2.2.2', 'master_port':53 } 
+        self.xfr.config_handler(master_info)
+        self.assertEqual(self.xfr._master_addr, '2.2.2.2')
+        self.assertEqual(self.xfr._master_port, 53)
+
 
 def raise_interrupt():
     raise KeyboardInterrupt()

Modified: trunk/src/bin/xfrin/xfrin.py.in
==============================================================================
--- trunk/src/bin/xfrin/xfrin.py.in (original)
+++ trunk/src/bin/xfrin/xfrin.py.in Mon Aug 16 09:05:52 2010
@@ -28,6 +28,7 @@
 import random
 from optparse import OptionParser, OptionValueError
 from isc.config.ccsession import *
+from isc.notify import notify_out
 try:
     from libdns_python import *
 except ImportError as e:
@@ -49,13 +50,17 @@
 SPECFILE_LOCATION = SPECFILE_PATH + "/xfrin.spec"
 AUTH_SPECFILE_LOCATION = AUTH_SPECFILE_PATH + "/auth.spec"
 
-
+XFROUT_MODULE_NAME = 'Xfrout'
+ZONE_MANAGER_MODULE_NAME = 'Zonemgr'
+REFRESH_FROM_ZONEMGR = 'refresh_from_zonemgr'
+ZONE_XFRIN_FAILED = 'zone_xfrin_failed'
 __version__ = 'BIND10'
 # define xfrin rcode
 XFRIN_OK = 0
 XFRIN_FAIL = 1
 
 DEFAULT_MASTER_PORT = '53'
+DEFAULT_MASTER = '127.0.0.1'
 
 def log_error(msg):
     sys.stderr.write("[b10-xfrin] %s\n" % str(msg))
@@ -316,14 +321,15 @@
             sys.stdout.write('[b10-xfrin] %s\n' % str(msg))
 
 
-def process_xfrin(xfrin_recorder, zone_name, rrclass, db_file, 
+def process_xfrin(server, xfrin_recorder, zone_name, rrclass, db_file, 
                   shutdown_event, master_addrinfo, check_soa, verbose):
     xfrin_recorder.increment(zone_name)
     sock_map = {}
     conn = XfrinConnection(sock_map, zone_name, rrclass, db_file,
                            shutdown_event, master_addrinfo, verbose)
     if conn.connect_to_master():
-        conn.do_xfrin(check_soa)
+        ret = conn.do_xfrin(check_soa)
+        server.publish_xfrin_news(zone_name, rrclass, ret)
 
     xfrin_recorder.decrement(zone_name)
 
@@ -358,32 +364,54 @@
 
 class Xfrin:
     def __init__(self, verbose = False):
+        self._max_transfers_in = 10
+        #TODO, this is the temp way to set the zone's master.
+        self._master_addr = DEFAULT_MASTER
+        self._master_port = DEFAULT_MASTER_PORT
         self._cc_setup()
-        self._max_transfers_in = 10
         self.recorder = XfrinRecorder()
         self._shutdown_event = threading.Event()
         self._verbose = verbose
 
     def _cc_setup(self):
-        '''
-This method is used only as part of initialization, but is implemented
-separately for convenience of unit tests; by letting the test code override
-this method we can test most of this class without requiring a command channel.
-'''
-        self._cc = isc.config.ModuleCCSession(SPECFILE_LOCATION,
+        '''This method is used only as part of initialization, but is 
+        implemented separately for convenience of unit tests; by letting 
+        the test code override this method we can test most of this class 
+        without requiring a command channel.'''
+        # Create one session for sending command to other modules, because the 
+        # listening session will block the send operation.
+        self._send_cc_session = isc.cc.Session()
+        self._module_cc = isc.config.ModuleCCSession(SPECFILE_LOCATION,
                                               self.config_handler,
                                               self.command_handler)
-        self._cc.start()
+        self._module_cc.start()
+        config_data = self._module_cc.get_full_config()
+        self._max_transfers_in = config_data.get("transfers_in")
+        self._master_addr = config_data.get('master_addr') or self._master_addr
+        self._master_port = config_data.get('master_port') or self._master_port
 
     def _cc_check_command(self):
-        '''
-This is a straightforward wrapper for cc.check_command, but provided as
-a separate method for the convenience of unit tests.
-'''
-        self._cc.check_command()
+        '''This is a straightforward wrapper for cc.check_command, 
+        but provided as a separate method for the convenience 
+        of unit tests.'''
+        self._module_cc.check_command()
 
     def config_handler(self, new_config):
-        # TODO, process new config data
+        self._max_transfers_in = new_config.get("transfers_in") or self._max_transfers_in
+        if ('master_addr' in new_config) or ('master_port' in new_config):
+            # Check if the new master is valid, there should be library for check it.
+            # and user should change the port and address together.
+            try:
+                addr = new_config.get('master_addr') or self._master_addr
+                port = new_config.get('master_port') or self._master_port
+                check_addr_port(addr, port)
+                self._master_addr = addr
+                self._master_port = port
+            except:
+                errmsg = "bad format for zone's master: " + str(new_config)
+                log_error(errmsg)
+                return create_answer(1, errmsg)
+
         return create_answer(0)
 
     def shutdown(self):
@@ -397,95 +425,97 @@
                 continue
             th.join()
 
-
     def command_handler(self, command, args):
         answer = create_answer(0)
         try:
             if command == 'shutdown':
                 self._shutdown_event.set()
+            elif command == 'notify' or command == REFRESH_FROM_ZONEMGR:
+                # Xfrin receives the refresh/notify command from zone manager. 
+                # notify command maybe has the parameters which 
+                # specify the notifyfrom address and port, according the RFC1996, zone
+                # transfer should starts first from the notifyfrom, but now, let 'TODO' it.
+                (zone_name, rrclass) = self._parse_zone_name_and_class(args)
+                (master_addr) = check_addr_port(self._master_addr, self._master_port)
+                ret = self.xfrin_start(zone_name, 
+                                       rrclass, 
+                                       self._get_db_file(),
+                                       master_addr,
+                                       True)
+                answer = create_answer(ret[0], ret[1])
+
             elif command == 'retransfer' or command == 'refresh':
-                (zone_name, rrclass,
-                 master_addr, db_file) = self._parse_cmd_params(args)
-                ret = self.xfrin_start(zone_name, rrclass, db_file,
+                # Xfrin receives the retransfer/refresh from cmdctl(sent by bindctl).
+                # If the command has specified master address, do transfer from the 
+                # master address, or else do transfer from the configured masters.                
+                (zone_name, rrclass) = self._parse_zone_name_and_class(args)
+                master_addr = self._parse_master_and_port(args)
+                db_file = args.get('db_file') or self._get_db_file()
+                ret = self.xfrin_start(zone_name, 
+                                       rrclass, 
+                                       db_file, 
                                        master_addr,
-                                   False if command == 'retransfer' else True)
+                                       (False if command == 'retransfer' else True))
                 answer = create_answer(ret[0], ret[1])
-            elif command == 'notify':
-                # This is the temporary implementation for notify.
-                # actually the notfiy command should be sent to the
-                # Zone Manager module.  Being temporary, we separate this case
-                # from refresh/retransfer while we could (and should otherwise)
-                # share the code.
-                (zone_name, rrclass,
-                 master_addr, db_file) = self._parse_cmd_params(args)
-
-                # XXX: master_addr is the sender of the notify message.
-                # It's very dangerous to naively trust it as the source of
-                # subsequent zone transfer; any remote node can easily exploit
-                # it to mount zone poisoning or DoS attacks.  We should
-                # locally identify the appropriate set of master servers.
-                # For now, we disable the code below.
-                master_is_valid = False
-
-                if master_is_valid:
-                    ret = self.xfrin_start(zone_name, rrclass, db_file,
-                                           master_addr, True)
-                else:
-                    errmsg = 'Failed to validate the master address ('
-                    errmsg += args['master'] + '), ignoring notify'
-                    ret = [1, errmsg]
-                answer = create_answer(ret[0], ret[1])
+
             else:
                 answer = create_answer(1, 'unknown command: ' + command)
-
         except XfrinException as err:
+            log_error('error happened for command: %s, %s' % (command, str(err)) )
             answer = create_answer(1, str(err))
-
         return answer
 
-    def _parse_cmd_params(self, args):
+    def _parse_zone_name_and_class(self, args):
         zone_name = args.get('zone_name')
         if not zone_name:
             raise XfrinException('zone name should be provided')
 
-        rrclass = args.get('rrclass')
+        rrclass = args.get('zone_class')
         if not rrclass:
-            # The default RR class is IN.  We should fix this so that
-            # the class is always passed in the command arg (where we specify
-            # the default)
             rrclass = RRClass.IN()
         else:
             try:
                 rrclass = RRClass(rrclass)
             except InvalidRRClass as e:
                 raise XfrinException('invalid RRClass: ' + rrclass)
-
-        master = args.get('master')
-        if not master:
-            raise XfrinException('master address should be provided')
-
-        port_str = args.get('port')
-        if not port_str:
-            port_str = DEFAULT_MASTER_PORT
-        master_addrinfo = check_addr_port(master, port_str)
-
-        db_file = args.get('db_file')
-        if not db_file:
-            #TODO, the db file path should be got in auth server's configuration
-            # if we need access to this configuration more often, we
-            # should add it on start, and not remove it here
-            # (or, if we have writable ds, we might not need this in
-            # the first place)
-            self._cc.add_remote_config(AUTH_SPECFILE_LOCATION)
-            db_file, is_default = self._cc.get_remote_config_value("Auth", "database_file")
-            if is_default and "B10_FROM_BUILD" in os.environ:
-                # this too should be unnecessary, but currently the
-                # 'from build' override isn't stored in the config
-                # (and we don't have writable datasources yet)
-                db_file = os.environ["B10_FROM_BUILD"] + os.sep + "bind10_zones.sqlite3"
-            self._cc.remove_remote_config(AUTH_SPECFILE_LOCATION)
-
-        return (zone_name, rrclass, master_addrinfo, db_file)
+        
+        return zone_name, rrclass
+
+    def _parse_master_and_port(self, args):
+        port = args.get('port') or self._master_port
+        master = args.get('master') or self._master_addr
+        return check_addr_port(master, port)
+ 
+    def _get_db_file(self):
+        #TODO, the db file path should be got in auth server's configuration
+        # if we need access to this configuration more often, we
+        # should add it on start, and not remove it here
+        # (or, if we have writable ds, we might not need this in
+        # the first place)
+        self._module_cc.add_remote_config(AUTH_SPECFILE_LOCATION)
+        db_file, is_default = self._module_cc.get_remote_config_value("Auth", "database_file")
+        if is_default and "B10_FROM_BUILD" in os.environ:
+            # this too should be unnecessary, but currently the
+            # 'from build' override isn't stored in the config
+            # (and we don't have writable datasources yet)
+            db_file = os.environ["B10_FROM_BUILD"] + os.sep + "bind10_zones.sqlite3"
+        self._module_cc.remove_remote_config(AUTH_SPECFILE_LOCATION)
+        return db_file
+       
+    def publish_xfrin_news(self, zone_name, zone_class,  xfr_result):
+        '''Send command to xfrout/zone manager module.
+        If xfrin has finished successfully for one zone, tell the good 
+        news(command: zone_new_data_ready) to zone manager and xfrout.
+        if xfrin failed, just tell the bad news to zone manager, so that 
+        it can reset the refresh timer for that zone. '''
+        param = {'zone_name': zone_name, 'zone_class': zone_class.to_text()}
+        if xfr_result == XFRIN_OK:
+            msg = create_command(notify_out.ZONE_NEW_DATA_READY_CMD, param)
+            self._send_cc_session.group_sendmsg(msg, XFROUT_MODULE_NAME)
+            self._send_cc_session.group_sendmsg(msg, ZONE_MANAGER_MODULE_NAME)
+        else:
+            msg = create_command(ZONE_XFRIN_FAILED, param)
+            self._send_cc_session.group_sendmsg(msg, ZONE_MANAGER_MODULE_NAME)
 
     def startup(self):
         while not self._shutdown_event.is_set():
@@ -504,7 +534,8 @@
             return (1, 'zone xfrin is in progress')
 
         xfrin_thread = threading.Thread(target = process_xfrin,
-                                        args = (self.recorder,
+                                        args = (self,
+                                                self.recorder,
                                                 zone_name, rrclass,
                                                 db_file,
                                                 self._shutdown_event,

Modified: trunk/src/bin/xfrin/xfrin.spec.pre.in
==============================================================================
--- trunk/src/bin/xfrin/xfrin.spec.pre.in (original)
+++ trunk/src/bin/xfrin/xfrin.spec.pre.in Mon Aug 16 09:05:52 2010
@@ -8,6 +8,17 @@
         "item_type": "integer",
         "item_optional": false,
         "item_default": 10
+      },
+      {
+        "item_name": "master_addr",
+        "item_type": "string",
+        "item_optional": false,
+        "item_default": ""
+      },
+      { "item_name": "master_port",
+        "item_type": "integer",
+        "item_optional": false,
+        "item_default": 53
       }
     ],
     "commands": [
@@ -21,9 +32,15 @@
             "item_default": ""
           },
           {
+            "item_name": "zone_class",
+            "item_type": "string",
+            "item_optional": true,
+            "item_default": "IN"
+          },
+          {
             "item_name": "master",
             "item_type": "string",
-            "item_optional": false,
+            "item_optional": true,
             "item_default": ""
           },
           {

Modified: trunk/src/bin/xfrout/xfrout.py.in
==============================================================================
--- trunk/src/bin/xfrout/xfrout.py.in (original)
+++ trunk/src/bin/xfrout/xfrout.py.in Mon Aug 16 09:05:52 2010
@@ -28,6 +28,7 @@
 from isc.config.ccsession import *
 from isc.log.log import *
 from isc.cc import SessionError
+from isc.notify import notify_out
 import socket
 import select
 import errno
@@ -303,7 +304,7 @@
         self._log = log
         self.update_config_data(config_data)
         self._cc = cc
-
+        
     def finish_request(self, request, client_address):
         '''Finish one request by instantiating RequestHandlerClass.'''
         self.RequestHandlerClass(request, client_address, self, self._log)
@@ -415,16 +416,25 @@
                                 self._config_data.get('log_severity'), self._config_data.get('log_versions'),
                                 self._config_data.get('log_max_bytes'), True)
         self._start_xfr_query_listener()
+        self._start_notifier()
 
     def _start_xfr_query_listener(self):
         '''Start a new thread to accept xfr query. '''
-    
         self._unix_socket_server = UnixSockServer(self._listen_sock_file, XfroutSession, 
                                                   self._shutdown_event, self._config_data,
                                                   self._cc, self._log);
         listener = threading.Thread(target = listen_on_xfr_query, args = (self._unix_socket_server,))
         listener.start()
-
+        
+    def _start_notifier(self):
+        datasrc = self._unix_socket_server.get_db_file()
+        self._notifier = notify_out.NotifyOut(datasrc, self._log)
+        td = threading.Thread(target = notify_out.dispatcher, args = (self._notifier,))
+        td.daemon = True
+        td.start()
+
+    def send_notify(self, zone_name, zone_class):
+        self._notifier.send_notify(zone_name, zone_class)
 
     def config_handler(self, new_config):
         '''Update config data. TODO. Do error check'''
@@ -466,11 +476,22 @@
             self._log.log_message("info", "Received shutdown command.")
             self.shutdown()
             answer = create_answer(0)
+        
+        elif cmd == notify_out.ZONE_NEW_DATA_READY_CMD:
+            zone_name = args.get('zone_name')
+            zone_class = args.get('zone_class')
+            if zone_name and zone_class:
+                self._log.log_message("info", "Receive notify command for zone:'%s/%s'" \
+                                     % (zone_name, zone_class))
+                self.send_notify(zone_name, zone_class)
+                answer = create_answer(0)
+            else:
+                answer = create_answer(1, "Bad command parameter:" + str(args))
+
         else: 
             answer = create_answer(1, "Unknown command:" + str(cmd))
 
         return answer    
- 
 
     def run(self):
         '''Get and process all commands sent from cfgmgr or other modules. '''

Modified: trunk/src/lib/python/isc/Makefile.am
==============================================================================
--- trunk/src/lib/python/isc/Makefile.am (original)
+++ trunk/src/lib/python/isc/Makefile.am Mon Aug 16 09:05:52 2010
@@ -1,4 +1,4 @@
-SUBDIRS = datasrc cc config log # Util
+SUBDIRS = datasrc cc config log notify # Util
 
 python_PYTHON = __init__.py
 

Modified: trunk/src/lib/python/isc/datasrc/sqlite3_ds.py
==============================================================================
--- trunk/src/lib/python/isc/datasrc/sqlite3_ds.py (original)
+++ trunk/src/lib/python/isc/datasrc/sqlite3_ds.py Mon Aug 16 09:05:52 2010
@@ -17,6 +17,13 @@
 
 import sqlite3, re, random
 import isc
+
+
+#define the index of different part of one record
+RR_TYPE_INDEX = 5
+RR_NAME_INDEX = 2
+RR_TTL_INDEX = 4
+RR_RDATA_INDEX = 7
 
 #########################################################################
 # define exceptions
@@ -120,6 +127,39 @@
 
     return datas
 
+
+#########################################################################
+# get_zone_rrset
+#   returns the rrset of the zone with the given zone name, rrset name 
+#   and given rd type. 
+#   If the zone doesn't exist or rd type doesn't exist, return an empty list. 
+#########################################################################
+def get_zone_rrset(zonename, rr_name, rdtype, dbfile):
+    conn, cur = open(dbfile)
+    id = get_zoneid(zonename, cur)
+    cur.execute("SELECT * FROM records WHERE name = ? and zone_id = ? and rdtype = ?", 
+                [rr_name, id, rdtype])
+    datas = cur.fetchall()
+    cur.close()
+    conn.close()
+    return datas
+
+
+#########################################################################
+# get_zones_info:
+#   returns all the zones' information.
+#########################################################################
+def get_zones_info(db_file):
+    conn, cur = open(db_file)
+    cur.execute("SELECT name, rdclass FROM zones")
+    info = cur.fetchone()
+    while info:
+        yield info
+        info = cur.fetchone()
+
+    cur.close()
+    conn.close()
+
 #########################################################################
 # get_zoneid:
 #   returns the zone_id for a given zone name, or an empty
@@ -132,7 +172,7 @@
         return row[0]
     else:
         return ''
-
+    
 #########################################################################
 # reverse_name:
 #   reverse the labels of a DNS name.  (for example,

Modified: trunk/src/lib/python/isc/notify/tests/notify_out_test.py
==============================================================================
--- trunk/src/lib/python/isc/notify/tests/notify_out_test.py (original)
+++ trunk/src/lib/python/isc/notify/tests/notify_out_test.py Mon Aug 16 09:05:52 2010
@@ -20,7 +20,7 @@
 import time
 import socket
 from isc.datasrc import sqlite3_ds
-import notify_out
+from isc.notify import notify_out
 
 class TestZoneNotifyInfo(unittest.TestCase):
     def setUp(self):




More information about the bind10-changes mailing list