BIND 10 master, updated. f99b625b66989c59fc7167b10c72325eaadff6cc [master] ChangeLog for #2225
BIND 10 source code commits
bind10-changes at lists.isc.org
Wed Feb 27 02:28:12 UTC 2013
The branch, master has been updated
via f99b625b66989c59fc7167b10c72325eaadff6cc (commit)
via 6df60554683165adacc2d1c3d29aa42a0c9141a1 (commit)
via 13e8c165b1fddbcb34868c1ed4731fb199b233e7 (commit)
via ab52e5a00f2bd30d6f2d5e38329f3955c9c23cbc (commit)
via 030a35c14145141b8ab1c656abb4892721da4e8c (commit)
via 6ac41c91691e92db70d6143f89ea1c9acb57c077 (commit)
via aed7be6f9f6c14a0006eb8a3693c554608100480 (commit)
via d21590b00ee8680cd45e4adf3c0c511da1f5348b (commit)
via 8bfa9b46bfef0f5282507ea0583897a7fd7ecd4a (commit)
via 6ed2eb91030b9935e97cd0fbdb6451adae34d65e (commit)
via 67b451a114650c1e4ccfc903a124c797fa6dc6fe (commit)
via 35c6e4a1b11669d7f82c5c4899e5ce0bc1be9ff0 (commit)
via e166275662c30de9f940643dace9f7844568b595 (commit)
via 7f64aa6706fe457ba91186d424f041931d455893 (commit)
via d7c19bfa03f33652626fea3fb0675dd8228a8005 (commit)
via 79a11d19f140d1420bc9d83dc1fbdcf907319418 (commit)
via 7390503b44baf97dc67ddaf800cd82b28f097d65 (commit)
via 5072f7f444a75c7152ed74135629748b4f71f584 (commit)
via eeaced2980d16428a1c523e1a0c77d7c7bd0ecb0 (commit)
via f99dea73ed9b124b72000b57f8ba8856f5838e9b (commit)
via 620caae79d9fd369f3872c82540a8ed80066bf12 (commit)
via 8013bd184be4669ec53274d1b174bc119a5a73b3 (commit)
via 7fbc8323cd986bda0e74941d76af727fb5b1df00 (commit)
via f8220e01112ddc39844db6bc69b5b66113f83641 (commit)
via 8b9c751d904bfd58f8be4d56e7c168c421794fc2 (commit)
via c98f15811814caf7bdf407864b88253f7311ecde (commit)
via f90889b6559cb2ba95a33108df1388afb5a12e7f (commit)
via 6392c36a0df416bf4476e2d5d3427105cbea98d7 (commit)
via 38896504bb750809442c77599b0c859a111b9789 (commit)
via a0033b21f7c50fe62b954bc501b8381e409966e8 (commit)
via 7016d0a7f2015d23d67b51cb594613a5ed619eba (commit)
via a2f8dd5d40c8c6c06ceb7278e6b8990f2a13e7dc (commit)
via 78a13fe9f10d8f2b982564e480ff375316dcf098 (commit)
via b3b2d10880821f7a434c32a0f3a7aabb6a1e5bf6 (commit)
via 6f6247afed0403bd27e9a70116445973750a646c (commit)
via bf26e302febe956fe4216ba1f1f3fc4590255090 (commit)
via b2c11d14542767ab608cf03da71e8f8332fc370b (commit)
via 365e3472c5ea96f3458097ba87f4270972c6eb8d (commit)
via 8733e86c9483dc5008c54ef37bac0e0455e9b877 (commit)
via c06c560406e56d49868c1fe593f5e8f64a00006f (commit)
via edbe6dfa75648a21b426a6075ccfe7ffc4ec2caf (commit)
via a81cba650f8324317dec95b4d95652521a5baf63 (commit)
from dc0f34afb1eccc574421a802557198e6cd2363fa (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit f99b625b66989c59fc7167b10c72325eaadff6cc
Author: Naoki Kambe <kambe at jprs.co.jp>
Date: Wed Feb 27 10:49:01 2013 +0900
[master] ChangeLog for #2225
commit 6df60554683165adacc2d1c3d29aa42a0c9141a1
Merge: dc0f34a 13e8c16
Author: Naoki Kambe <kambe at jprs.co.jp>
Date: Wed Feb 27 10:44:35 2013 +0900
[master] Merge branch 'trac2225_xfrout'
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 7 +
src/bin/xfrin/tests/Makefile.am | 1 +
src/bin/xfrin/xfrin.py.in | 18 +-
src/bin/xfrout/b10-xfrout.xml | 159 +++++++--
src/bin/xfrout/tests/xfrout_test.py.in | 369 +++++++++-----------
src/bin/xfrout/xfrout.py.in | 261 ++++----------
src/bin/xfrout/xfrout.spec.pre.in | 108 +++++-
src/bin/xfrout/xfrout_messages.mes | 2 +-
src/lib/python/isc/notify/notify_out.py | 25 +-
src/lib/python/isc/notify/tests/notify_out_test.py | 99 +++---
.../lettuce/features/xfrin_notify_handling.feature | 96 ++++-
11 files changed, 637 insertions(+), 508 deletions(-)
-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index fa50a5d..d7af227 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+582. [func] naokikambe
+ New statistics items related unixdomain sockets added into Xfrout :
+ open, openfail, close, bindfail, acceptfail, accept, senderr, and
+ recverr. Their values can be obtained by invoking "Stats show Xfrout"
+ via bindctl while Xfrout is running.
+ (Trac #2225, git 6df60554683165adacc2d1c3d29aa42a0c9141a1)
+
581. [func]* y-aharen
Added statistics items in b10-auth based on
http://bind10.isc.org/wiki/StatisticsItems. Qtype counters are
diff --git a/src/bin/xfrin/tests/Makefile.am b/src/bin/xfrin/tests/Makefile.am
index cba98ae..c1ca278 100644
--- a/src/bin/xfrin/tests/Makefile.am
+++ b/src/bin/xfrin/tests/Makefile.am
@@ -28,5 +28,6 @@ endif
TESTDATASRCDIR=$(abs_top_srcdir)/src/bin/xfrin/tests/testdata/ \
TESTDATAOBJDIR=$(abs_top_builddir)/src/bin/xfrin/tests/testdata/ \
B10_FROM_BUILD=$(abs_top_builddir) \
+ B10_FROM_SOURCE=$(abs_top_srcdir) \
$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
done
diff --git a/src/bin/xfrin/xfrin.py.in b/src/bin/xfrin/xfrin.py.in
index 011d995..65a27bb 100755
--- a/src/bin/xfrin/xfrin.py.in
+++ b/src/bin/xfrin/xfrin.py.in
@@ -48,17 +48,17 @@ DBG_COMMANDS = logger.DBGLVL_TRACE_DETAIL
isc.util.process.rename()
-# If B10_FROM_BUILD is set in the environment, we use data files
-# from a directory relative to that, otherwise we use the ones
-# installed on the system
+# If B10_FROM_BUILD or B10_FROM_SOURCE is set in the environment, we
+# use data files from a directory relative to that, otherwise we use
+# the ones installed on the system
+SPECFILE_PATH = "@datadir@/@PACKAGE@"\
+ .replace("${datarootdir}", "@datarootdir@")\
+ .replace("${prefix}", "@prefix@")
+AUTH_SPECFILE_PATH = SPECFILE_PATH
+if "B10_FROM_SOURCE" in os.environ:
+ SPECFILE_PATH = os.environ["B10_FROM_SOURCE"] + "/src/bin/xfrin"
if "B10_FROM_BUILD" in os.environ:
- SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/xfrin"
AUTH_SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/auth"
-else:
- PREFIX = "@prefix@"
- DATAROOTDIR = "@datarootdir@"
- SPECFILE_PATH = "@datadir@/@PACKAGE@".replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
- AUTH_SPECFILE_PATH = SPECFILE_PATH
SPECFILE_LOCATION = SPECFILE_PATH + "/xfrin.spec"
AUTH_SPECFILE_LOCATION = AUTH_SPECFILE_PATH + "/auth.spec"
diff --git a/src/bin/xfrout/b10-xfrout.xml b/src/bin/xfrout/b10-xfrout.xml
index 2b201d0..5c71e05 100644
--- a/src/bin/xfrout/b10-xfrout.xml
+++ b/src/bin/xfrout/b10-xfrout.xml
@@ -164,53 +164,154 @@
<variablelist>
<varlistentry>
- <term>notifyoutv4</term>
+ <term>zones</term>
<listitem><simpara>
- Number of IPv4 notifies per zone name sent out from Xfrout
- </simpara></listitem>
- </varlistentry>
-
- <varlistentry>
- <term>notifyoutv6</term>
- <listitem><simpara>
- Number of IPv6 notifies per zone name sent out from Xfrout
- </simpara></listitem>
- </varlistentry>
-
- <varlistentry>
- <term>xfrrej</term>
- <listitem><simpara>
- Number of XFR requests per zone name rejected by Xfrout
- </simpara></listitem>
- </varlistentry>
+ A directory name of per-zone statistics
+ </simpara>
+ <variablelist>
+
+ <varlistentry>
+ <term><replaceable>zonename</replaceable></term>
+ <listitem><simpara>
+ A actual zone name or special zone name <quote>_SERVER_</quote>
+ representing an entire server
+ </simpara>
+ <variablelist>
+
+ <varlistentry>
+ <term>notifyoutv4</term>
+ <listitem><simpara>
+ Number of IPv4 notifies per zone name sent out from Xfrout
+ </simpara></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>notifyoutv6</term>
+ <listitem><simpara>
+ Number of IPv6 notifies per zone name sent out from Xfrout
+ </simpara></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>xfrrej</term>
+ <listitem><simpara>
+ Number of XFR requests per zone name rejected by Xfrout
+ </simpara></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>xfrreqdone</term>
+ <listitem><simpara>
+ Number of requested zone transfers per zone name completed
+ </simpara></listitem>
+ </varlistentry>
+
+ </variablelist>
+ </listitem>
+ </varlistentry><!-- end of zonename -->
+
+ </variablelist>
+ </listitem>
+ </varlistentry><!-- end of zones -->
<varlistentry>
- <term>xfrreqdone</term>
+ <term>ixfr_running</term>
<listitem><simpara>
- Number of requested zone transfers per zone name completed
+ Number of IXFRs in progress
</simpara></listitem>
</varlistentry>
<varlistentry>
- <term>ixfr_running</term>
+ <term>axfr_running</term>
<listitem><simpara>
- Number of IXFRs in progress
+ Number of AXFRs in progress
</simpara></listitem>
</varlistentry>
<varlistentry>
- <term>axfr_running</term>
+ <term>socket</term>
<listitem><simpara>
- Number of AXFRs in progress
- </simpara></listitem>
- </varlistentry>
+ A directory name of socket statistics
+ </simpara>
+ <variablelist>
+
+ <varlistentry>
+ <term>unixdomain</term>
+ <listitem><simpara>
+ A directory name of UNIX domain statistics
+ </simpara>
+ <variablelist>
+
+ <varlistentry>
+ <term>open</term>
+ <listitem><simpara>
+ UNIX domain sockets opened successfully
+ </simpara></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>openfail</term>
+ <listitem><simpara>
+ UNIX domain sockets open failures
+ </simpara></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>close</term>
+ <listitem><simpara>
+ UNIX domain sockets closed
+ </simpara></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>bindfail</term>
+ <listitem><simpara>
+ UNIX domain sockets bind failures
+ </simpara></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>acceptfail</term>
+ <listitem><simpara>
+ UNIX domain sockets incoming accept failures
+ </simpara></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>accept</term>
+ <listitem><simpara>
+ UNIX domain sockets incoming connections successfully accepted
+ </simpara></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>senderr</term>
+ <listitem><simpara>
+ UNIX domain sockets send errors
+ </simpara></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>recverr</term>
+ <listitem><simpara>
+ UNIX domain sockets receive errors
+ </simpara></listitem>
+ </varlistentry>
+
+ </variablelist>
+ </listitem>
+ </varlistentry><!-- end of unixdomain -->
+
+ </variablelist>
+ </listitem>
+ </varlistentry><!-- end of socket -->
</variablelist>
<para>
- In per-zone counters the special zone name '_SERVER_' exists. It doesn't
- mean a specific zone. It represents an entire server and its value means
- a total count of all zones.
+ In per-zone counters the special zone name <quote>_SERVER_</quote> exists.
+ It doesn't mean a specific zone. It represents an entire server and its
+ value means a total count of all zones.
</para>
</refsect1>
diff --git a/src/bin/xfrout/tests/xfrout_test.py.in b/src/bin/xfrout/tests/xfrout_test.py.in
index bc0fae9..2802ace 100644
--- a/src/bin/xfrout/tests/xfrout_test.py.in
+++ b/src/bin/xfrout/tests/xfrout_test.py.in
@@ -270,7 +270,6 @@ class TestXfroutSessionBase(unittest.TestCase):
def setUp(self):
self.sock = MySocket(socket.AF_INET,socket.SOCK_STREAM)
- self.setup_counters()
self.xfrsess = MyXfroutSession(self.sock, None, Dbserver(),
TSIGKeyRing(),
(socket.AF_INET, socket.SOCK_STREAM,
@@ -278,8 +277,7 @@ class TestXfroutSessionBase(unittest.TestCase):
# When not testing ACLs, simply accept
isc.acl.dns.REQUEST_LOADER.load(
[{"action": "ACCEPT"}]),
- {},
- **self._counters)
+ {})
self.set_request_type(RRType.AXFR) # test AXFR by default
self.mdata = self.create_request_data()
self.soa_rrset = create_soa(SOA_CURRENT_VERSION)
@@ -287,52 +285,13 @@ class TestXfroutSessionBase(unittest.TestCase):
# original is used elsewhere.
self.orig_get_rrset_len = xfrout.get_rrset_len
- def setup_counters(self):
- self._statistics_data = {
- 'zones' : {
- TEST_ZONE_NAME_STR : {
- 'xfrrej': 0,
- 'xfrreqdone': 0
- }
- },
- 'axfr_started': 0,
- 'ixfr_started': 0,
- 'axfr_ended': 0,
- 'ixfr_ended': 0
- }
- def _counter_xfrrej(zone_name):
- self._statistics_data['zones'][zone_name]['xfrrej'] += 1
- def _counter_xfrreqdone(zone_name):
- self._statistics_data['zones'][zone_name]['xfrreqdone'] += 1
- def _inc_ixfr_running():
- self._statistics_data['ixfr_started'] += 1
- def _dec_ixfr_running():
- self._statistics_data['ixfr_ended'] += 1
- def _inc_axfr_running():
- self._statistics_data['axfr_started'] += 1
- def _dec_axfr_running():
- self._statistics_data['axfr_ended'] += 1
- self._counters = {
- 'counter_xfrrej': _counter_xfrrej,
- 'counter_xfrreqdone': _counter_xfrreqdone,
- 'inc_ixfr_running': _inc_ixfr_running,
- 'dec_ixfr_running': _dec_ixfr_running,
- 'inc_axfr_running': _inc_axfr_running,
- 'dec_axfr_running': _dec_axfr_running
- }
-
- def get_counter(self, name):
- if name.find('ixfr_') == 0 or name.find('axfr_') == 0:
- return self._statistics_data[name]
- else:
- return \
- self._statistics_data['zones'][TEST_ZONE_NAME_STR][name]
-
def tearDown(self):
xfrout.get_rrset_len = self.orig_get_rrset_len
# transfer_counter must be always be reset no matter happens within
# the XfroutSession object. We check the condition here.
self.assertEqual(0, self.xfrsess._server.transfer_counter)
+ # clear statistics counters
+ self.xfrsess._counters.clear_all()
class TestXfroutSession(TestXfroutSessionBase):
def test_quota_error(self):
@@ -420,7 +379,9 @@ class TestXfroutSession(TestXfroutSessionBase):
}
]))
# check the 'xfrrej' counter initially
- self.assertEqual(self.get_counter('xfrrej'), 0)
+ self.assertRaises(isc.cc.data.DataNotFoundError,
+ self.xfrsess._counters.get, 'zones',
+ TEST_ZONE_NAME_STR, 'xfrrej')
# Localhost (the default in this test) is accepted
rcode, msg = self.xfrsess._parse_query_message(self.mdata)
self.assertEqual(rcode.to_text(), "NOERROR")
@@ -435,7 +396,8 @@ class TestXfroutSession(TestXfroutSessionBase):
rcode, msg = self.xfrsess._parse_query_message(self.mdata)
self.assertEqual(rcode.to_text(), "REFUSED")
# check the 'xfrrej' counter after incrementing
- self.assertEqual(self.get_counter('xfrrej'), 1)
+ self.assertEqual(self.xfrsess._counters.get(
+ 'zones', TEST_ZONE_NAME_STR, 'xfrrej'), 1)
# TSIG signed request
request_data = self.create_request_data(with_tsig=True)
@@ -465,7 +427,8 @@ class TestXfroutSession(TestXfroutSessionBase):
[rcode, msg] = self.xfrsess._parse_query_message(request_data)
self.assertEqual(rcode.to_text(), "REFUSED")
# check the 'xfrrej' counter after incrementing
- self.assertEqual(self.get_counter('xfrrej'), 2)
+ self.assertEqual(self.xfrsess._counters.get(
+ 'zones', TEST_ZONE_NAME_STR, 'xfrrej'), 2)
# ACL using TSIG: no TSIG; should be rejected
acl_setter(isc.acl.dns.REQUEST_LOADER.load([
@@ -474,7 +437,8 @@ class TestXfroutSession(TestXfroutSessionBase):
[rcode, msg] = self.xfrsess._parse_query_message(self.mdata)
self.assertEqual(rcode.to_text(), "REFUSED")
# check the 'xfrrej' counter after incrementing
- self.assertEqual(self.get_counter('xfrrej'), 3)
+ self.assertEqual(self.xfrsess._counters.get(
+ 'zones', TEST_ZONE_NAME_STR, 'xfrrej'), 3)
#
# ACL using IP + TSIG: both should match
@@ -495,21 +459,24 @@ class TestXfroutSession(TestXfroutSessionBase):
[rcode, msg] = self.xfrsess._parse_query_message(request_data)
self.assertEqual(rcode.to_text(), "REFUSED")
# check the 'xfrrej' counter after incrementing
- self.assertEqual(self.get_counter('xfrrej'), 4)
+ self.assertEqual(self.xfrsess._counters.get(
+ 'zones', TEST_ZONE_NAME_STR, 'xfrrej'), 4)
# Address matches, but TSIG doesn't (not included)
self.xfrsess._remote = (socket.AF_INET, socket.SOCK_STREAM,
('192.0.2.1', 12345))
[rcode, msg] = self.xfrsess._parse_query_message(self.mdata)
self.assertEqual(rcode.to_text(), "REFUSED")
# check the 'xfrrej' counter after incrementing
- self.assertEqual(self.get_counter('xfrrej'), 5)
+ self.assertEqual(self.xfrsess._counters.get(
+ 'zones', TEST_ZONE_NAME_STR, 'xfrrej'), 5)
# Neither address nor TSIG matches
self.xfrsess._remote = (socket.AF_INET, socket.SOCK_STREAM,
('192.0.2.2', 12345))
[rcode, msg] = self.xfrsess._parse_query_message(self.mdata)
self.assertEqual(rcode.to_text(), "REFUSED")
# check the 'xfrrej' counter after incrementing
- self.assertEqual(self.get_counter('xfrrej'), 6)
+ self.assertEqual(self.xfrsess._counters.get(
+ 'zones', TEST_ZONE_NAME_STR, 'xfrrej'), 6)
def test_transfer_acl(self):
# ACL checks only with the default ACL
@@ -517,14 +484,6 @@ class TestXfroutSession(TestXfroutSessionBase):
self.xfrsess._acl = acl
self.check_transfer_acl(acl_setter)
- def test_transfer_acl_with_notcallable_xfrrej(self):
- # ACL checks only with the default ACL and not callable xfrrej
- # counter
- def acl_setter(acl):
- self.xfrsess._acl = acl
- self.xfrsess._counter_xfrrej = 'NOT CALLABLE'
- self.assertRaises(TypeError,
- self.check_transfer_acl, acl_setter)
def test_transfer_zoneacl(self):
# ACL check with a per zone ACL + default ACL. The per zone ACL
@@ -889,21 +848,25 @@ class TestXfroutSession(TestXfroutSessionBase):
self.xfrsess.dns_xfrout_start(self.sock, self.mdata)
self.assertEqual(self.sock.read_msg().get_rcode(), Rcode.SERVFAIL)
- def test_dns_xfrout_start_noerror(self):
+ def test_dns_xfrout_start_unixsocketsenderr(self):
+ """This test is for a counter senderr of unixsocket."""
+
def noerror(msg, name, rrclass):
return Rcode.NOERROR
self.xfrsess._xfrout_setup = noerror
def myreply(msg, sock):
- self.sock.send(b"success")
+ raise Exception
- self.assertEqual(self.get_counter('xfrreqdone'), 0)
self.xfrsess._reply_xfrout_query = myreply
+ self.assertRaises(isc.cc.data.DataNotFoundError,
+ self.xfrsess._counters.get,
+ 'socket', 'unixdomain', 'senderr')
self.xfrsess.dns_xfrout_start(self.sock, self.mdata)
- self.assertEqual(self.sock.readsent(), b"success")
- self.assertGreater(self.get_counter('xfrreqdone'), 0)
+ self.assertEqual(self.xfrsess._counters.get(
+ 'socket', 'unixdomain', 'senderr'), 1)
- def test_dns_xfrout_start_with_notcallable_xfrreqdone(self):
+ def test_dns_xfrout_start_noerror(self):
def noerror(msg, name, rrclass):
return Rcode.NOERROR
self.xfrsess._xfrout_setup = noerror
@@ -911,11 +874,14 @@ class TestXfroutSession(TestXfroutSessionBase):
def myreply(msg, sock):
self.sock.send(b"success")
+ self.assertRaises(isc.cc.data.DataNotFoundError,
+ self.xfrsess._counters.get,
+ 'zones', TEST_ZONE_NAME_STR, 'xfrreqdone')
self.xfrsess._reply_xfrout_query = myreply
- self.xfrsess._counter_xfrreqdone = 'NOT CALLABLE'
- self.assertRaises(TypeError,
- self.xfrsess.dns_xfrout_start, self.sock,
- self.mdata)
+ self.xfrsess.dns_xfrout_start(self.sock, self.mdata)
+ self.assertEqual(self.sock.readsent(), b"success")
+ self.assertGreater(self.xfrsess._counters.get(
+ 'zones', TEST_ZONE_NAME_STR, 'xfrreqdone'), 0)
def test_reply_xfrout_query_axfr(self):
self.xfrsess._soa = self.soa_rrset
@@ -1171,20 +1137,17 @@ class TestXfroutSessionWithSQLite3(TestXfroutSessionBase):
self.assertTrue(rrsets_equal(expected_rr, actual_rr))
def test_axfr_normal_session(self):
- self.assertEqual(self.get_counter('axfr_started'), 0)
- self.assertEqual(self.get_counter('axfr_ended'), 0)
- self.assertEqual(self.get_counter('ixfr_started'), 0)
- self.assertEqual(self.get_counter('ixfr_ended'), 0)
+ self.assertRaises(isc.cc.data.DataNotFoundError,
+ self.xfrsess._counters.get, 'axfr_running')
XfroutSession._handle(self.xfrsess)
response = self.sock.read_msg(Message.PRESERVE_ORDER);
self.assertEqual(Rcode.NOERROR, response.get_rcode())
self.check_axfr_stream(response)
self.assertEqual(self.xfrsess._request_type, RRType.AXFR)
self.assertNotEqual(self.xfrsess._request_type, RRType.IXFR)
- self.assertEqual(self.get_counter('axfr_started'), 1)
- self.assertEqual(self.get_counter('axfr_ended'), 1)
- self.assertEqual(self.get_counter('ixfr_started'), 0)
- self.assertEqual(self.get_counter('ixfr_ended'), 0)
+ self.assertRaises(isc.cc.data.DataNotFoundError,
+ self.xfrsess._counters.get, 'ixfr_running')
+ self.assertEqual(self.xfrsess._counters.get('axfr_running'), 0)
def test_ixfr_to_axfr(self):
self.xfrsess._request_data = \
@@ -1203,10 +1166,10 @@ class TestXfroutSessionWithSQLite3(TestXfroutSessionBase):
# two beginning and trailing SOAs.
self.xfrsess._request_data = \
self.create_request_data(ixfr=IXFR_OK_VERSION)
- self.assertEqual(self.get_counter('axfr_started'), 0)
- self.assertEqual(self.get_counter('axfr_ended'), 0)
- self.assertEqual(self.get_counter('ixfr_started'), 0)
- self.assertEqual(self.get_counter('ixfr_ended'), 0)
+ self.assertRaises(isc.cc.data.DataNotFoundError,
+ self.xfrsess._counters.get, 'axfr_running')
+ self.assertRaises(isc.cc.data.DataNotFoundError,
+ self.xfrsess._counters.get, 'ixfr_running')
XfroutSession._handle(self.xfrsess)
response = self.sock.read_msg(Message.PRESERVE_ORDER)
actual_records = response.get_section(Message.SECTION_ANSWER)
@@ -1224,10 +1187,9 @@ class TestXfroutSessionWithSQLite3(TestXfroutSessionBase):
self.assertTrue(rrsets_equal(expected_rr, actual_rr))
self.assertNotEqual(self.xfrsess._request_type, RRType.AXFR)
self.assertEqual(self.xfrsess._request_type, RRType.IXFR)
- self.assertEqual(self.get_counter('axfr_started'), 0)
- self.assertEqual(self.get_counter('axfr_ended'), 0)
- self.assertEqual(self.get_counter('ixfr_started'), 1)
- self.assertEqual(self.get_counter('ixfr_ended'), 1)
+ self.assertRaises(isc.cc.data.DataNotFoundError,
+ self.xfrsess._counters.get, 'axfr_running')
+ self.assertEqual(self.xfrsess._counters.get('ixfr_running'), 0)
def ixfr_soa_only_common_checks(self, request_serial):
self.xfrsess._request_data = \
@@ -1255,7 +1217,7 @@ class MyUnixSockServer(UnixSockServer):
self._common_init()
self._cc = MyCCSession()
self.update_config_data(self._cc.get_full_config())
- self._counters = {}
+ self._counters = xfrout.Counters(xfrout.SPECFILE_LOCATION)
class TestUnixSockServer(unittest.TestCase):
def setUp(self):
@@ -1561,6 +1523,130 @@ class TestUnixSockServer(unittest.TestCase):
self.unix._select_loop(self.__select_return_redable[0])
self.assertEqual(1, self.__select_count)
+class DummyBaseSocketserver():
+ def shutdown(self): pass
+ def send(self, arg): pass
+ def get_request(self): pass
+
+class DummySocketserver(DummyBaseSocketserver):
+ def __init__(self, *args): pass
+
+class DummySocketserverException(DummyBaseSocketserver):
+ def __init__(self, *args): raise Exception
+
+class TestUnixSockServerForCounter(unittest.TestCase):
+
+ def setUp(self):
+ ( self.orig_remove_unused_sock_file,
+ self.orig_update_config_data,
+ self.orig_socket_socketpair,
+ self.orig_NoPollMixIn,
+ self.orig_ThreadingUnixStreamServer,
+ self.orig_process_request,
+ self.orig_select ) = \
+ ( UnixSockServer._remove_unused_sock_file,
+ UnixSockServer.update_config_data,
+ xfrout.socket.socketpair,
+ xfrout.socketserver_mixin.NoPollMixIn,
+ xfrout.ThreadingUnixStreamServer,
+ UnixSockServer.process_request,
+ xfrout.select.select )
+ UnixSockServer._remove_unused_sock_file = lambda x,y: None
+ UnixSockServer.update_config_data = lambda x,y: None
+ xfrout.socket.socketpair = \
+ lambda : (DummySocketserver(), DummySocketserver())
+ xfrout.socketserver_mixin.NoPollMixIn = DummySocketserver
+ xfrout.ThreadingUnixStreamServer = DummySocketserver
+ xfrout.super = lambda : DummySocketserver()
+ xfrout.select.select = lambda x,y,z: ([None],[None],[None])
+ self.unix = UnixSockServer(None, None, threading.Event(), None, None)
+
+ def tearDown(self):
+ ( UnixSockServer._remove_unused_sock_file,
+ UnixSockServer.update_config_data,
+ xfrout.socket.socketpair,
+ xfrout.socketserver_mixin.NoPollMixIn,
+ xfrout.ThreadingUnixStreamServer,
+ xfrout.super,
+ UnixSockServer.process_request,
+ xfrout.select.select ) = \
+ ( self.orig_remove_unused_sock_file,
+ self.orig_update_config_data,
+ self.orig_socket_socketpair,
+ self.orig_NoPollMixIn,
+ self.orig_ThreadingUnixStreamServer,
+ super,
+ self.orig_process_request,
+ self.orig_select )
+ self.unix._counters.clear_all()
+
+ def test_open(self):
+ # open
+ self.assertEqual(
+ self.unix._counters.get('socket', 'unixdomain', 'open'), 1)
+ self.assertRaises(isc.cc.data.DataNotFoundError,
+ self.unix._counters.get,
+ 'socket', 'unixdomain', 'openfail')
+ xfrout.ThreadingUnixStreamServer = DummySocketserverException
+ try:
+ self.unix = UnixSockServer(None, None, None, None, None)
+ except Exception:
+ pass
+ else:
+ self.fail("an exception should be raised")
+ self.assertEqual(
+ self.unix._counters.get('socket', 'unixdomain', 'open'), 1)
+ self.assertEqual(
+ self.unix._counters.get('socket', 'unixdomain', 'openfail'), 1)
+
+ def test_close(self):
+ # close
+ self.assertRaises(isc.cc.data.DataNotFoundError,
+ self.unix._counters.get,
+ 'socket','unixdomain', 'close')
+ self.unix.shutdown()
+ self.assertEqual(
+ self.unix._counters.get('socket', 'unixdomain', 'close'), 1)
+
+ def test_bindfail(self):
+ # bindfail
+ self.assertRaises(isc.cc.data.DataNotFoundError,
+ self.unix._counters.get,
+ 'socket', 'unixdomain', 'bindfail')
+ self.assertRaises(Exception, self.unix.server_bind)
+ self.assertEqual(
+ self.unix._counters.get('socket', 'unixdomain', 'bindfail'), 1)
+
+ def test_accept(self):
+ # accept
+ self.assertRaises(isc.cc.data.DataNotFoundError,
+ self.unix._counters.get,
+ 'socket', 'unixdomain', 'accept')
+ self.unix.get_request()
+ self.assertEqual(
+ self.unix._counters.get('socket', 'unixdomain', 'accept'), 1)
+ # acceptfail
+ self.assertRaises(isc.cc.data.DataNotFoundError,
+ self.unix._counters.get,
+ 'socket', 'unixdomain', 'acceptfail')
+ xfrout.super = lambda : DummyClassException()
+ self.unix = UnixSockServer(None, None, None, None, None)
+ self.assertRaises(Exception, self.unix.get_request)
+ self.assertEqual(
+ self.unix._counters.get('socket', 'unixdomain', 'acceptfail'), 1)
+
+ def test_recverr(self):
+ # recverr
+ self.assertRaises(isc.cc.data.DataNotFoundError,
+ self.unix._counters.get,
+ 'socket', 'unixdomain', 'recverr')
+ def raise_socketerror(x,y):
+ raise socket.error
+ self.unix.process_request = raise_socketerror
+ self.unix._select_loop(None)
+ self.assertEqual(self.unix._counters.get(
+ 'socket', 'unixdomain', 'recverr'), 1)
+
class TestInitialization(unittest.TestCase):
def setEnv(self, name, value):
if value is None:
@@ -1609,116 +1695,7 @@ class MyXfroutServer(XfroutServer):
self._wait_for_threads = lambda : None
self._cc.get_module_spec = lambda:\
isc.config.module_spec_from_file(xfrout.SPECFILE_LOCATION)
- # setup an XfroutCount object
- self._counter = XfroutCounter(
- self._cc.get_module_spec().get_statistics_spec())
-
-class TestXfroutCounter(unittest.TestCase):
- def setUp(self):
- self._module_spec = isc.config.module_spec_from_file(\
- xfrout.SPECFILE_LOCATION)
- statistics_spec = self._module_spec.get_statistics_spec()
- self.xfrout_counter = XfroutCounter(statistics_spec)
- self._counters = isc.config.spec_name_list(\
- isc.config.find_spec_part(\
- statistics_spec, XfroutCounter.perzone_prefix)\
- ['named_set_item_spec']['map_item_spec'])
- self._started = threading.Event()
- self._number = 3 # number of the threads
- self._cycle = 10000 # number of counting per thread
-
- def test_get_default_statistics_data(self):
- self.assertTrue(\
- self._module_spec.validate_statistics(\
- True,
- self.xfrout_counter._get_default_statistics_data(),
- )
- )
-
- def setup_incrementer(self, incrementer, *args):
- self._started.wait()
- for i in range(self._cycle): incrementer(*args)
-
- def start_incrementer(self, incrementer, *args):
- threads = []
- for i in range(self._number):
- threads.append(threading.Thread(\
- target=self.setup_incrementer, \
- args=(incrementer,) + args \
- ))
- for th in threads: th.start()
- self._started.set()
- for th in threads: th.join()
-
- def get_count(self, zone_name, counter_name):
- return isc.cc.data.find(\
- self.xfrout_counter.get_statistics(),\
- '%s/%s/%s' % (XfroutCounter.perzone_prefix,\
- zone_name, counter_name))
-
- def test_incdecrementers(self):
- # for per-zone counters
- result = { XfroutCounter.entire_server: {},
- TEST_ZONE_NAME_STR: {} }
- for counter_name in self._counters:
- cntrs_xfrss = \
- self.xfrout_counter.get_counters_for_xfroutsession()
- cntrs_notfy = \
- self.xfrout_counter.get_counters_for_notifyout()
- cnt_name = 'counter_%s' % counter_name
- incrementer = None
- if cnt_name in cntrs_xfrss:
- incrementer = cntrs_xfrss[cnt_name]
- else:
- incrementer = cntrs_notfy[cnt_name]
- self.start_incrementer(incrementer, TEST_ZONE_NAME_STR)
- self.assertEqual(self.get_count(\
- TEST_ZONE_NAME_STR, counter_name), \
- self._number * self._cycle)
- self.assertEqual(self.get_count(\
- XfroutCounter.entire_server, counter_name), \
- self._number * self._cycle)
- result[XfroutCounter.entire_server][counter_name] = \
- result[TEST_ZONE_NAME_STR][counter_name] = \
- self._number * self._cycle
- statistics_data = {XfroutCounter.perzone_prefix: result}
-
- # for {a|i}xfrrunning counters
- for counter_name in self.xfrout_counter._xfrrunning_names:
- incrementer = \
- dict(self.xfrout_counter.get_counters_for_xfroutsession(), \
- **self.xfrout_counter.get_counters_for_notifyout())\
- ['inc_%s' % counter_name]
- self.start_incrementer(incrementer)
- self.assertEqual(
- self.xfrout_counter.get_statistics()[counter_name],
- self._number * self._cycle
- )
- decrementer = \
- dict(self.xfrout_counter.get_counters_for_xfroutsession(), \
- **self.xfrout_counter.get_counters_for_notifyout())\
- ['dec_%s' % counter_name]
- self.start_incrementer(decrementer)
- self.assertEqual(
- self.xfrout_counter.get_statistics()[counter_name],
- 0)
- statistics_data[counter_name] = 0
- self.assertEqual(
- self.xfrout_counter.get_statistics(),
- statistics_data)
- self.assertTrue(\
- self._module_spec.validate_statistics(\
- True, statistics_data
- )
- )
-
- def test_add_perzone_counter(self):
- for counter_name in self._counters:
- self.assertRaises(isc.cc.data.DataNotFoundError,\
- self.get_count, TEST_ZONE_NAME_STR, counter_name)
- self.xfrout_counter._add_perzone_counter(TEST_ZONE_NAME_STR)
- for counter_name in self._counters:
- self.assertEqual(self.get_count(TEST_ZONE_NAME_STR, counter_name), 0)
+ self._counters = xfrout.Counters(xfrout.SPECFILE_LOCATION)
class TestXfroutServer(unittest.TestCase):
def setUp(self):
diff --git a/src/bin/xfrout/xfrout.py.in b/src/bin/xfrout/xfrout.py.in
index 5d25276..d6ef360 100755
--- a/src/bin/xfrout/xfrout.py.in
+++ b/src/bin/xfrout/xfrout.py.in
@@ -27,6 +27,7 @@ from socketserver import *
import os
from isc.config.ccsession import *
from isc.cc import SessionError, SessionTimeout
+from isc.statistics import Counters
from isc.notify import notify_out
import isc.util.process
import socket
@@ -153,8 +154,7 @@ def get_soa_serial(soa_rdata):
class XfroutSession():
def __init__(self, sock_fd, request_data, server, tsig_key_ring, remote,
- default_acl, zone_config, client_class=DataSourceClient,
- **counters):
+ default_acl, zone_config, client_class=DataSourceClient):
self._sock_fd = sock_fd
self._request_data = request_data
self._server = server
@@ -169,13 +169,9 @@ class XfroutSession():
self.ClientClass = client_class # parameterize this for testing
self._soa = None # will be set in _xfrout_setup or in tests
self._jnl_reader = None # will be set to a reader for IXFR
- # Extract counter handler from the `counters` argument and add
- # it to the class attribute of the name whose prefix is
- # '_counter_' '_inc_' or '_dec_'
- for (k, v) in counters.items():
- if k.find('counter_') == 0 or k.find('inc_') == 0 \
- or k.find('dec_') == 0:
- setattr(self, "_%s" % k, v)
+ # Creation of self.counters should be done before of
+ # invoking self._handle()
+ self._counters = Counters(SPECFILE_LOCATION)
self._handle()
def create_tsig_ctx(self, tsig_record, tsig_key_ring):
@@ -279,7 +275,7 @@ class XfroutSession():
return None, None
elif acl_result == REJECT:
# count rejected Xfr request by each zone name
- self._counter_xfrrej(zone_name.to_text())
+ self._counters.inc('zones', zone_name.to_text(), 'xfrrej')
logger.debug(DBG_XFROUT_TRACE, XFROUT_QUERY_REJECTED,
self._request_type, format_addrinfo(self._remote),
format_zone_str(zone_name, zone_class))
@@ -531,23 +527,25 @@ class XfroutSession():
try:
# increment Xfr starts by RRType
if self._request_type == RRType.AXFR:
- self._inc_axfr_running()
+ self._counters.inc('axfr_running')
else:
- self._inc_ixfr_running()
+ self._counters.inc('ixfr_running')
logger.info(XFROUT_XFR_TRANSFER_STARTED, self._request_typestr,
format_addrinfo(self._remote), zone_str)
self._reply_xfrout_query(msg, sock_fd)
except Exception as err:
+ # count unixsockets send errors
+ self._counters.inc('socket', 'unixdomain', 'senderr')
logger.error(XFROUT_XFR_TRANSFER_ERROR, self._request_typestr,
format_addrinfo(self._remote), zone_str, err)
finally:
# decrement Xfr starts by RRType
if self._request_type == RRType.AXFR:
- self._dec_axfr_running()
+ self._counters.dec('axfr_running')
else:
- self._dec_ixfr_running()
+ self._counters.dec('ixfr_running')
# count done Xfr requests by each zone name
- self._counter_xfrreqdone(zone_name.to_text())
+ self._counters.inc('zones', zone_name.to_text(), 'xfrreqdone')
logger.info(XFROUT_XFR_TRANSFER_DONE, self._request_typestr,
format_addrinfo(self._remote), zone_str)
@@ -657,18 +655,53 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn,
'''The unix domain socket server which accept xfr query sent from auth server.'''
def __init__(self, sock_file, handle_class, shutdown_event, config_data,
- cc, **counters):
+ cc):
self._remove_unused_sock_file(sock_file)
self._sock_file = sock_file
socketserver_mixin.NoPollMixIn.__init__(self)
- ThreadingUnixStreamServer.__init__(self, sock_file, handle_class)
+ self._counters = Counters(SPECFILE_LOCATION)
+ try:
+ ThreadingUnixStreamServer.__init__(self, sock_file, \
+ handle_class)
+ except:
+ self._counters.inc('socket', 'unixdomain', 'openfail')
+ raise
+ else:
+ self._counters.inc('socket', 'unixdomain', 'open')
self._shutdown_event = shutdown_event
self._write_sock, self._read_sock = socket.socketpair()
self._common_init()
self._cc = cc
self.update_config_data(config_data)
- # handlers for statistics use
- self._counters = counters
+
+ def server_bind(self):
+ """server_bind() overridden for counting unix domain sockets
+ bind() failures
+ """
+ try:
+ # call the server_bind() of class
+ # ThreadingUnixStreamServer
+ return super().server_bind()
+ except:
+ # count bind failed unixsockets
+ self._counters.inc('socket', 'unixdomain', 'bindfail')
+ raise
+
+ def get_request(self):
+ """get_request() overridden for counting unix domain sockets
+ accept() failures and success
+ """
+ try:
+ # call the get_request() of class
+ # ThreadingUnixStreamServer
+ ret = super().get_request()
+ # count successfully accepted unixsockets
+ self._counters.inc('socket', 'unixdomain', 'accept')
+ return ret
+ except:
+ # count failed accepted unixsockets
+ self._counters.inc('socket', 'unixdomain', 'acceptfail')
+ raise
def _common_init(self):
'''Initialization shared with the mock server class used for tests'''
@@ -736,6 +769,8 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn,
if not self.process_request(request_sock):
break
except Exception as pre:
+ # count unixsockets receive errors
+ self._counters.inc('socket', 'unixdomain', 'recverr')
logger.error(XFROUT_PROCESS_REQUEST_ERROR, pre)
break
@@ -823,8 +858,7 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn,
self._lock.release()
self.RequestHandlerClass(sock_fd, request_data, self,
isc.server_common.tsig_keyring.get_keyring(),
- self._guess_remote(sock_fd), acl, zone_config,
- **self._counters)
+ self._guess_remote(sock_fd), acl, zone_config)
def _remove_unused_sock_file(self, sock_file):
'''Try to remove the socket file. If the file is being used
@@ -861,6 +895,8 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn,
def shutdown(self):
self._write_sock.send(b"shutdown") #terminate the xfrout session thread
super().shutdown() # call the shutdown() of class socketserver_mixin.NoPollMixIn
+ # count closed unixsockets
+ self._counters.inc('socket', 'unixdomain', 'close')
try:
os.unlink(self._sock_file)
except Exception as e:
@@ -952,172 +988,6 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn,
self._transfers_counter -= 1
self._lock.release()
-class XfroutCounter:
- """A class for handling all statistics counters of Xfrout. In
- this class, the structure of per-zone counters is assumed to be
- like this:
- zones/example.com./notifyoutv4
- zones/example.com./notifyoutv6
- zones/example.com./xfrrej
- zones/example.com./xfrreqdone
- ixfr_running
- axfr_running
- """
- # '_SERVER_' is a special zone name representing an entire
- # count. It doesn't mean a specific zone, but it means an
- # entire count in the server.
- entire_server = '_SERVER_'
- # zone names are contained under this dirname in the spec file.
- perzone_prefix = 'zones'
- def __init__(self, statistics_spec):
- self._statistics_spec = statistics_spec
- # holding statistics data for Xfrout module
- self._statistics_data = {}
- self._counters_for_xfroutsession = {}
- self._counters_for_notifyout = {}
- self._xfrrunning_names = [
- n for n in isc.config.spec_name_list\
- (self._statistics_spec) \
- if n.find('xfr_running') == 1 ]
- self._lock = threading.RLock()
- self._create_perzone_incrementers()
- self._create_xfrrunning_incdecrementers()
-
- def get_statistics(self):
- """Calculates an entire server counts, and returns statistics
- data format to send out the stats module including each
- counter. If there is no counts, then it returns an empty
- dictionary. Locks the thread because it is considered to be
- invoked by a multi-threading caller."""
- # If self._statistics_data contains nothing of zone name, it
- # returns an empty dict.
- if len(self._statistics_data) == 0: return {}
- # for per-zone counter
- zones = {}
- zones = self._statistics_data[self.perzone_prefix]
- # Start calculation for '_SERVER_' counts
- attrs = self._get_default_statistics_data()[self.perzone_prefix][self.entire_server]
- statistics_data = {self.perzone_prefix: {}}
- for attr in attrs:
- sum_ = 0
- for name in zones:
- if name == self.entire_server: continue
- if attr in zones[name]:
- if name not in statistics_data[self.perzone_prefix]:
- statistics_data[self.perzone_prefix][name] = {}
- statistics_data[self.perzone_prefix][name].update(
- {attr: zones[name][attr]}
- )
- sum_ += zones[name][attr]
- if sum_ > 0:
- if self.entire_server not in statistics_data[self.perzone_prefix]:
- statistics_data[self.perzone_prefix][self.entire_server] = {}
- statistics_data[self.perzone_prefix][self.entire_server]\
- .update({attr:sum_})
- # for xfrrunning incrementer/decrementer
- for name in self._xfrrunning_names:
- if name in self._statistics_data:
- statistics_data[name] = self._statistics_data[name]
- return statistics_data
-
- def _get_default_statistics_data(self):
- """Returns default statistics data from the spec file"""
- statistics_data = {}
- for id_ in isc.config.spec_name_list(self._statistics_spec):
- spec = isc.config.find_spec_part(self._statistics_spec, id_)
- statistics_data.update({id_: spec['item_default']})
- return statistics_data
-
- def _create_perzone_incrementers(self):
- """Creates increment method of each per-zone counter based on
- the spec file. Incrementer can be accessed by name
- "inc_${item_name}".Incrementers are passed to the
- XfroutSession and NotifyOut class as counter handlers."""
- # add a new element under the named_set item for the zone
- zones_spec = isc.config.find_spec_part(
- self._statistics_spec, self.perzone_prefix)
- item_list = isc.config.spec_name_list(\
- zones_spec['named_set_item_spec']['map_item_spec'])
- # can be accessed by the name 'inc_xxx'
- for item in item_list:
- def __perzone_incrementer(zone_name, counter_name=item, step=1):
- """A per-zone incrementer for counter_name. Locks the thread
- because it is considered to be invoked by a multi-threading
- caller."""
- with self._lock:
- self._add_perzone_counter(zone_name)
- self._statistics_data[self.perzone_prefix][zone_name][counter_name] += step
- if 'notifyout' in item:
- self._counters_for_notifyout['counter_%s' % item] \
- = __perzone_incrementer
- else:
- self._counters_for_xfroutsession['counter_%s' % item] \
- = __perzone_incrementer
-
- def _create_xfrrunning_incdecrementers(self):
- """Creates increment/decrement method of (a|i)xfr_running
- based on the spec file. Incrementer can be accessed by name
- "inc_${item_name}". Decrementer can be accessed by name
- "dec_${item_name}". Both of them are passed to the
- XfroutSession as counter handlers."""
- # can be accessed by the name 'inc_xxx' or 'dec_xxx'
- for item in self._xfrrunning_names:
- def __xfrrunning_incrementer(counter_name=item, step=1):
- """A incrementer for axfr or ixfr running. Locks the thread
- because it is considered to be invoked by a multi-threading
- caller."""
- with self._lock:
- self._add_xfrrunning_counter(counter_name)
- self._statistics_data[counter_name] += step
- def __xfrrunning_decrementer(counter_name=item, step=-1):
- """A decrementer for axfr or ixfr running. Locks the thread
- because it is considered to be invoked by a multi-threading
- caller."""
- with self._lock:
- self._statistics_data[counter_name] += step
- self._counters_for_xfroutsession['inc_%s' % item] \
- = __xfrrunning_incrementer
- self._counters_for_xfroutsession['dec_%s' % item] \
- = __xfrrunning_decrementer
-
- def get_counters_for_xfroutsession(self):
- """Returns counters, incrementers, and decrementers to be
- passed to XfroutSession/UnixSockServer class."""
- return self._counters_for_xfroutsession
-
- def get_counters_for_notifyout(self):
- """Returns counters handlers to be passed to NotifyOut
- class."""
- return self._counters_for_notifyout
-
- def _add_perzone_counter(self, zone):
- """Adds a named_set-type counter for each zone name."""
- try:
- self._statistics_data[self.perzone_prefix][zone]
- except KeyError:
- # add a new element under the named_set item for the zone
- map_spec = isc.config.find_spec_part(
- self._statistics_spec, '%s/%s' % \
- (self.perzone_prefix, zone))['map_item_spec']
- id_list = isc.config.spec_name_list(map_spec)
- for id_ in id_list:
- spec = isc.config.find_spec_part(map_spec, id_)
- isc.cc.data.set(self._statistics_data,
- '%s/%s/%s' % \
- (self.perzone_prefix, zone, id_),
- spec['item_default'])
-
- def _add_xfrrunning_counter(self, counter_name):
- """Adds a counter for counting (a|i)xfr_running"""
- try:
- self._statistics_data[counter_name]
- except KeyError:
- # examines the names of xfer running
- for n in self._xfrrunning_names:
- spec = isc.config.find_spec_part(self._statistics_spec, n)
- isc.cc.data.set(self._statistics_data, n, \
- spec['item_default'])
-
class XfroutServer:
def __init__(self):
self._unix_socket_server = None
@@ -1125,13 +995,12 @@ class XfroutServer:
self._shutdown_event = threading.Event()
self._cc = isc.config.ModuleCCSession(SPECFILE_LOCATION, self.config_handler, self.command_handler)
self._config_data = self._cc.get_full_config()
- self._counter = XfroutCounter(
- self._cc.get_module_spec().get_statistics_spec())
self._cc.start()
self._cc.add_remote_config(AUTH_SPECFILE_LOCATION)
isc.server_common.tsig_keyring.init_keyring(self._cc)
self._start_xfr_query_listener()
self._start_notifier()
+ self._counters = Counters(SPECFILE_LOCATION)
def _start_xfr_query_listener(self):
'''Start a new thread to accept xfr query. '''
@@ -1140,18 +1009,13 @@ class XfroutServer:
XfroutSession,
self._shutdown_event,
self._config_data,
- self._cc,
- **self._counter.get_counters_for_xfroutsession()
- )
+ self._cc)
listener = threading.Thread(target=self._unix_socket_server.serve_forever)
listener.start()
def _start_notifier(self):
datasrc = self._unix_socket_server.get_db_file()
- self._notifier = notify_out.NotifyOut(
- datasrc,
- **self._counter.get_counters_for_notifyout()
- )
+ self._notifier = notify_out.NotifyOut(datasrc)
if 'also_notify' in self._config_data:
for slave in self._config_data['also_notify']:
self._notifier.add_slave(slave['address'], slave['port'])
@@ -1232,9 +1096,10 @@ class XfroutServer:
# The log level is here set to debug in order to avoid
# that a log becomes too verbose. Because the b10-stats
# daemon is periodically asking to the b10-xfrout daemon.
+ answer = create_answer(0, self._counters.get_statistics())
logger.debug(DBG_XFROUT_TRACE, \
- XFROUT_RECEIVED_GETSTATS_COMMAND)
- answer = create_answer(0, self._counter.get_statistics())
+ XFROUT_RECEIVED_GETSTATS_COMMAND, \
+ str(answer))
else:
answer = create_answer(1, "Unknown command:" + str(cmd))
diff --git a/src/bin/xfrout/xfrout.spec.pre.in b/src/bin/xfrout/xfrout.spec.pre.in
index 1d24be2..4277c3b 100644
--- a/src/bin/xfrout/xfrout.spec.pre.in
+++ b/src/bin/xfrout/xfrout.spec.pre.in
@@ -129,14 +129,14 @@
}
},
"item_title": "Zone names",
- "item_description": "Zone names for Xfrout statistics",
+ "item_description": "A directory name of per-zone statistics",
"named_set_item_spec": {
"item_name": "zonename",
"item_type": "map",
"item_optional": false,
"item_default": {},
"item_title": "Zone name",
- "item_description": "Zone name for Xfrout statistics",
+ "item_description": "A actual zone name or special zone name _SERVER_ representing an entire server",
"map_item_spec": [
{
"item_name": "notifyoutv4",
@@ -188,6 +188,110 @@
"item_default": 0,
"item_title": "AXFR running",
"item_description": "Number of AXFRs in progress"
+ },
+ {
+ "item_name": "socket",
+ "item_type": "map",
+ "item_optional": false,
+ "item_default": {
+ "unixdomain": {
+ "open": 0,
+ "openfail": 0,
+ "close": 0,
+ "bindfail": 0,
+ "acceptfail": 0,
+ "accept": 0,
+ "senderr": 0,
+ "recverr": 0
+ }
+ },
+ "item_title": "Socket",
+ "item_description": "A directory name of socket statistics",
+ "map_item_spec": [
+ {
+ "item_name": "unixdomain",
+ "item_type": "map",
+ "item_optional": false,
+ "item_default": {
+ "open": 0,
+ "openfail": 0,
+ "close": 0,
+ "bindfail": 0,
+ "acceptfail": 0,
+ "accept": 0,
+ "senderr": 0,
+ "recverr": 0
+ },
+ "item_title": "UNIX domain",
+ "item_description": "A directory name of UNIX domain statistics",
+ "map_item_spec": [
+ {
+ "item_name": "open",
+ "item_type": "integer",
+ "item_optional": false,
+ "item_default": 0,
+ "item_title": "Open",
+ "item_description": "UNIX domain sockets opened successfully"
+ },
+ {
+ "item_name": "openfail",
+ "item_type": "integer",
+ "item_optional": false,
+ "item_default": 0,
+ "item_title": "Open failures",
+ "item_description": "UNIX domain sockets open failures"
+ },
+ {
+ "item_name": "close",
+ "item_type": "integer",
+ "item_optional": false,
+ "item_default": 0,
+ "item_title": "Close",
+ "item_description": "UNIX domain sockets closed"
+ },
+ {
+ "item_name": "bindfail",
+ "item_type": "integer",
+ "item_optional": false,
+ "item_default": 0,
+ "item_title": "Bind failures",
+ "item_description": "UNIX domain sockets bind failures"
+ },
+ {
+ "item_name": "acceptfail",
+ "item_type": "integer",
+ "item_optional": false,
+ "item_default": 0,
+ "item_title": "Accept failures",
+ "item_description": "UNIX domain sockets incoming accept failures"
+ },
+ {
+ "item_name": "accept",
+ "item_type": "integer",
+ "item_optional": false,
+ "item_default": 0,
+ "item_title": "Accept",
+ "item_description": "UNIX domain sockets incoming connections successfully accepted"
+ },
+ {
+ "item_name": "senderr",
+ "item_type": "integer",
+ "item_optional": false,
+ "item_default": 0,
+ "item_title": "Send errors",
+ "item_description": "UNIX domain sockets send errors"
+ },
+ {
+ "item_name": "recverr",
+ "item_type": "integer",
+ "item_optional": false,
+ "item_default": 0,
+ "item_title": "Receive errors",
+ "item_description": "UNIX domain sockets receive errors"
+ }
+ ]
+ }
+ ]
}
]
}
diff --git a/src/bin/xfrout/xfrout_messages.mes b/src/bin/xfrout/xfrout_messages.mes
index 5fb254e..d49981d 100644
--- a/src/bin/xfrout/xfrout_messages.mes
+++ b/src/bin/xfrout/xfrout_messages.mes
@@ -147,7 +147,7 @@ given host. This is because of ACLs. The %2 represents the IP
address and port of the peer requesting the transfer, and the %3
represents the zone name and class.
-% XFROUT_RECEIVED_GETSTATS_COMMAND received command to get statistics data
+% XFROUT_RECEIVED_GETSTATS_COMMAND received command to send statistics data: %1
The xfrout daemon received a command on the command channel that
statistics data should be sent to the stats daemon.
diff --git a/src/lib/python/isc/notify/notify_out.py b/src/lib/python/isc/notify/notify_out.py
index 1f75256..d1ec2e9 100644
--- a/src/lib/python/isc/notify/notify_out.py
+++ b/src/lib/python/isc/notify/notify_out.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2010 Internet Systems Consortium.
+# Copyright (C) 2010-2012 Internet Systems Consortium.
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
@@ -25,6 +25,7 @@ from isc.datasrc import DataSourceClient
from isc.net import addr
import isc
from isc.log_messages.notify_out_messages import *
+from isc.statistics import Counters
logger = isc.log.Logger("notify_out")
@@ -127,8 +128,7 @@ class NotifyOut:
notify message to its slaves). notify service can be started by
calling dispatcher(), and it can be stopped by calling shutdown()
in another thread. '''
- def __init__(self, datasrc_file, counter_handler=None, verbose=True,
- counter_notifyoutv4=None, counter_notifyoutv6=None):
+ def __init__(self, datasrc_file, verbose=True):
self._notify_infos = {} # key is (zone_name, zone_class)
self._waiting_zones = []
self._notifying_zones = []
@@ -143,10 +143,7 @@ class NotifyOut:
# Use nonblock event to eliminate busy loop
# If there are no notifying zones, clear the event bit and wait.
self._nonblock_event = threading.Event()
- # Set counter handlers for counting notifies. An argument is
- # required for zone name.
- self._counter_notifyoutv4 = counter_notifyoutv4
- self._counter_notifyoutv6 = counter_notifyoutv6
+ self._counters = Counters()
def _init_notify_out(self, datasrc_file):
'''Get all the zones name and its notify target's address.
@@ -484,14 +481,12 @@ class NotifyOut:
sock = zone_notify_info.create_socket(addrinfo[0])
sock.sendto(render.get_data(), 0, addrinfo)
# count notifying by IPv4 or IPv6 for statistics
- if zone_notify_info.get_socket().family \
- == socket.AF_INET \
- and self._counter_notifyoutv4 is not None:
- self._counter_notifyoutv4(zone_notify_info.zone_name)
- elif zone_notify_info.get_socket().family \
- == socket.AF_INET6 \
- and self._counter_notifyoutv6 is not None:
- self._counter_notifyoutv6(zone_notify_info.zone_name)
+ if zone_notify_info.get_socket().family == socket.AF_INET:
+ self._counters.inc('zones', zone_notify_info.zone_name,
+ 'notifyoutv4')
+ elif zone_notify_info.get_socket().family == socket.AF_INET6:
+ self._counters.inc('zones', zone_notify_info.zone_name,
+ 'notifyoutv6')
logger.info(NOTIFY_OUT_SENDING_NOTIFY, addrinfo[0],
addrinfo[1])
except (socket.error, addr.InvalidAddress) as err:
diff --git a/src/lib/python/isc/notify/tests/notify_out_test.py b/src/lib/python/isc/notify/tests/notify_out_test.py
index ad1107f..3b2324d 100644
--- a/src/lib/python/isc/notify/tests/notify_out_test.py
+++ b/src/lib/python/isc/notify/tests/notify_out_test.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2010 Internet Systems Consortium.
+# Copyright (C) 2010-2012 Internet Systems Consortium.
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
@@ -96,13 +96,7 @@ class TestZoneNotifyInfo(unittest.TestCase):
class TestNotifyOut(unittest.TestCase):
def setUp(self):
self._db_file = TESTDATA_SRCDIR + '/test.sqlite3'
- self._notifiedv4_zone_name = None
- def _dummy_counter_notifyoutv4(z): self._notifiedv4_zone_name = z
- self._notifiedv6_zone_name = None
- def _dummy_counter_notifyoutv6(z): self._notifiedv6_zone_name = z
- self._notify = notify_out.NotifyOut(self._db_file,
- counter_notifyoutv4=_dummy_counter_notifyoutv4,
- counter_notifyoutv6=_dummy_counter_notifyoutv6)
+ self._notify = notify_out.NotifyOut(self._db_file)
self._notify._notify_infos[('example.com.', 'IN')] = MockZoneNotifyInfo('example.com.', 'IN')
self._notify._notify_infos[('example.com.', 'CH')] = MockZoneNotifyInfo('example.com.', 'CH')
self._notify._notify_infos[('example.net.', 'IN')] = MockZoneNotifyInfo('example.net.', 'IN')
@@ -117,6 +111,9 @@ class TestNotifyOut(unittest.TestCase):
com_ch_info = self._notify._notify_infos[('example.com.', 'CH')]
com_ch_info.notify_slaves.append(('1.1.1.1', 5353))
+ def tearDown(self):
+ self._notify._counters.clear_all()
+
def test_send_notify(self):
notify_out._MAX_NOTIFY_NUM = 2
@@ -268,77 +265,67 @@ class TestNotifyOut(unittest.TestCase):
def test_send_notify_message_udp_ipv4(self):
example_com_info = self._notify._notify_infos[('example.net.', 'IN')]
+
+ self.assertRaises(isc.cc.data.DataNotFoundError,
+ self._notify._counters.get,
+ 'zones', 'example.net.', 'notifyoutv4')
+ self.assertRaises(isc.cc.data.DataNotFoundError,
+ self._notify._counters.get,
+ 'zones', 'example.net.', 'notifyoutv6')
+
example_com_info.prepare_notify_out()
- self.assertIsNone(self._notifiedv4_zone_name)
- self.assertIsNone(self._notifiedv6_zone_name)
ret = self._notify._send_notify_message_udp(example_com_info,
('192.0.2.1', 53))
self.assertTrue(ret)
self.assertEqual(socket.AF_INET, example_com_info.sock_family)
- self.assertEqual(self._notifiedv4_zone_name, 'example.net.')
- self.assertIsNone(self._notifiedv6_zone_name)
+ self.assertEqual(self._notify._counters.get(
+ 'zones', 'example.net.', 'notifyoutv4'), 1)
+ self.assertEqual(self._notify._counters.get(
+ 'zones', 'example.net.', 'notifyoutv6'), 0)
def test_send_notify_message_udp_ipv6(self):
example_com_info = self._notify._notify_infos[('example.net.', 'IN')]
- self.assertIsNone(self._notifiedv4_zone_name)
- self.assertIsNone(self._notifiedv6_zone_name)
+
+ self.assertRaises(isc.cc.data.DataNotFoundError,
+ self._notify._counters.get,
+ 'zones', 'example.net.', 'notifyoutv4')
+ self.assertRaises(isc.cc.data.DataNotFoundError,
+ self._notify._counters.get,
+ 'zones', 'example.net.', 'notifyoutv6')
+
ret = self._notify._send_notify_message_udp(example_com_info,
('2001:db8::53', 53))
self.assertTrue(ret)
self.assertEqual(socket.AF_INET6, example_com_info.sock_family)
- self.assertIsNone(self._notifiedv4_zone_name)
- self.assertEqual(self._notifiedv6_zone_name, 'example.net.')
-
- def test_send_notify_message_udp_ipv4_with_nonetype_notifyoutv4(self):
- example_com_info = self._notify._notify_infos[('example.net.', 'IN')]
- example_com_info.prepare_notify_out()
- self.assertIsNone(self._notifiedv4_zone_name)
- self.assertIsNone(self._notifiedv6_zone_name)
- self._notify._counter_notifyoutv4 = None
- self._notify._send_notify_message_udp(example_com_info,
- ('192.0.2.1', 53))
- self.assertIsNone(self._notifiedv4_zone_name)
- self.assertIsNone(self._notifiedv6_zone_name)
-
- def test_send_notify_message_udp_ipv4_with_notcallable_notifyoutv4(self):
- example_com_info = self._notify._notify_infos[('example.net.', 'IN')]
- example_com_info.prepare_notify_out()
- self._notify._counter_notifyoutv4 = 'NOT CALLABLE'
- self.assertRaises(TypeError,
- self._notify._send_notify_message_udp,
- example_com_info, ('192.0.2.1', 53))
-
- def test_send_notify_message_udp_ipv6_with_nonetype_notifyoutv6(self):
- example_com_info = self._notify._notify_infos[('example.net.', 'IN')]
- self.assertIsNone(self._notifiedv4_zone_name)
- self.assertIsNone(self._notifiedv6_zone_name)
- self._notify._counter_notifyoutv6 = None
- self._notify._send_notify_message_udp(example_com_info,
- ('2001:db8::53', 53))
- self.assertIsNone(self._notifiedv4_zone_name)
- self.assertIsNone(self._notifiedv6_zone_name)
-
- def test_send_notify_message_udp_ipv6_with_notcallable_notifyoutv6(self):
- example_com_info = self._notify._notify_infos[('example.net.', 'IN')]
- self._notify._counter_notifyoutv6 = 'NOT CALLABLE'
- self.assertRaises(TypeError,
- self._notify._send_notify_message_udp,
- example_com_info, ('2001:db8::53', 53))
+ self.assertEqual(self._notify._counters.get(
+ 'zones', 'example.net.', 'notifyoutv4'), 0)
+ self.assertEqual(self._notify._counters.get(
+ 'zones', 'example.net.', 'notifyoutv6'), 1)
def test_send_notify_message_with_bogus_address(self):
example_com_info = self._notify._notify_infos[('example.net.', 'IN')]
+ self.assertRaises(isc.cc.data.DataNotFoundError,
+ self._notify._counters.get,
+ 'zones', 'example.net.', 'notifyoutv4')
+ self.assertRaises(isc.cc.data.DataNotFoundError,
+ self._notify._counters.get,
+ 'zones', 'example.net.', 'notifyoutv6')
+
# As long as the underlying data source validates RDATA this shouldn't
# happen, but right now it's not actually the case. Even if the
# data source does its job, it's prudent to confirm the behavior for
# an unexpected case.
- self.assertIsNone(self._notifiedv4_zone_name)
- self.assertIsNone(self._notifiedv6_zone_name)
ret = self._notify._send_notify_message_udp(example_com_info,
('invalid', 53))
self.assertFalse(ret)
- self.assertIsNone(self._notifiedv4_zone_name)
- self.assertIsNone(self._notifiedv6_zone_name)
+
+ self.assertRaises(isc.cc.data.DataNotFoundError,
+ self._notify._counters.get,
+ 'zones', 'example.net.', 'notifyoutv4')
+ self.assertRaises(isc.cc.data.DataNotFoundError,
+ self._notify._counters.get,
+ 'zones', 'example.net.', 'notifyoutv4')
def test_zone_notify_handler(self):
old_send_msg = self._notify._send_notify_message_udp
diff --git a/tests/lettuce/features/xfrin_notify_handling.feature b/tests/lettuce/features/xfrin_notify_handling.feature
index 03b18c1..e3f2642 100644
--- a/tests/lettuce/features/xfrin_notify_handling.feature
+++ b/tests/lettuce/features/xfrin_notify_handling.feature
@@ -34,11 +34,19 @@ Feature: Xfrin incoming notify handling
When I query statistics ixfr_running of bind10 module Xfrout with cmdctl port 47804
Then the statistics counter ixfr_running should be 0
- Then the statistics counter ixfr_running should be 0
When I query statistics axfr_running of bind10 module Xfrout with cmdctl port 47804
Then the statistics counter axfr_running should be 0
- Then the statistics counter axfr_running should be 0
+
+ When I query statistics socket of bind10 module Xfrout with cmdctl port 47804
+ Then the statistics counter open should be between 0 and 1
+ Then the statistics counter openfail should be 0
+ Then the statistics counter close should be 0
+ Then the statistics counter bindfail should be 0
+ Then the statistics counter acceptfail should be 0
+ Then the statistics counter accept should be 0
+ Then the statistics counter senderr should be 0
+ Then the statistics counter recverr should be 0
When I send bind10 with cmdctl port 47804 the command Xfrout notify example.org IN
Then wait for new master stderr message XFROUT_NOTIFY_COMMAND
@@ -73,6 +81,16 @@ Feature: Xfrin incoming notify handling
Then the statistics counter xfrreqdone for the zone _SERVER_ should be 1
Then the statistics counter xfrreqdone for the zone example.org. should be 1
+ When I query statistics socket of bind10 module Xfrout with cmdctl port 47804
+ Then the statistics counter open should be 1
+ Then the statistics counter openfail should be 0
+ Then the statistics counter close should be 0
+ Then the statistics counter bindfail should be 0
+ Then the statistics counter acceptfail should be 0
+ Then the statistics counter accept should be 1
+ Then the statistics counter senderr should be 0
+ Then the statistics counter recverr should be 0
+
#
# Test for Xfr request rejected
#
@@ -107,6 +125,22 @@ Feature: Xfrin incoming notify handling
Then the statistics counter xfrrej for the zone _SERVER_ should be 0
Then the statistics counter xfrreqdone for the zone _SERVER_ should be 0
+ When I query statistics ixfr_running of bind10 module Xfrout with cmdctl port 47804
+ Then the statistics counter ixfr_running should be 0
+
+ When I query statistics axfr_running of bind10 module Xfrout with cmdctl port 47804
+ Then the statistics counter axfr_running should be 0
+
+ When I query statistics socket of bind10 module Xfrout with cmdctl port 47804
+ Then the statistics counter open should be between 0 and 1
+ Then the statistics counter openfail should be 0
+ Then the statistics counter close should be 0
+ Then the statistics counter bindfail should be 0
+ Then the statistics counter acceptfail should be 0
+ Then the statistics counter accept should be 0
+ Then the statistics counter senderr should be 0
+ Then the statistics counter recverr should be 0
+
#
# set transfer_acl rejection
# Local xfr requests from Xfrin module would be rejected here.
@@ -152,3 +186,61 @@ Feature: Xfrin incoming notify handling
Then the statistics counter xfrrej for the zone example.org. should be greater than 0
Then the statistics counter xfrreqdone for the zone _SERVER_ should be 0
Then the statistics counter xfrreqdone for the zone example.org. should be 0
+
+ When I query statistics socket of bind10 module Xfrout with cmdctl port 47804
+ Then the statistics counter open should be 1
+ Then the statistics counter openfail should be 0
+ Then the statistics counter close should be 0
+ Then the statistics counter bindfail should be 0
+ Then the statistics counter acceptfail should be 0
+ Then the statistics counter accept should be 1
+ Then the statistics counter senderr should be 0
+ Then the statistics counter recverr should be 0
+
+ #
+ # Test for unreachable slave
+ #
+ Scenario: Handle incoming notify (unreachable slave)
+ Given I have bind10 running with configuration xfrin/retransfer_master.conf with cmdctl port 47804 as master
+ And wait for master stderr message BIND10_STARTED_CC
+ And wait for master stderr message CMDCTL_STARTED
+ And wait for master stderr message AUTH_SERVER_STARTED
+ And wait for master stderr message XFROUT_STARTED
+ And wait for master stderr message ZONEMGR_STARTED
+ And wait for master stderr message STATS_STARTING
+
+ When I send bind10 with cmdctl port 47804 the command Xfrout notify example.org IN
+ Then wait for new master stderr message XFROUT_NOTIFY_COMMAND
+ Then wait for new master stderr message NOTIFY_OUT_SENDING_NOTIFY
+ Then wait for new master stderr message NOTIFY_OUT_TIMEOUT
+
+ #
+ # Test1 for Xfrout statistics
+ #
+ # check statistics change
+ #
+
+ # wait until the last stats requesting is finished
+ wait for new master stderr message STATS_SEND_STATISTICS_REQUEST
+ wait for new master stderr message XFROUT_RECEIVED_GETSTATS_COMMAND
+
+ When I query statistics zones of bind10 module Xfrout with cmdctl port 47804
+ last bindctl output should not contain "error"
+ Then the statistics counter notifyoutv4 for the zone _SERVER_ should be 0
+ Then the statistics counter notifyoutv4 for the zone example.org. should be 0
+ Then the statistics counter notifyoutv6 for the zone _SERVER_ should be greater than 0
+ Then the statistics counter notifyoutv6 for the zone example.org. should be greater than 0
+ Then the statistics counter xfrrej for the zone _SERVER_ should be 0
+ Then the statistics counter xfrrej for the zone example.org. should be 0
+ Then the statistics counter xfrreqdone for the zone _SERVER_ should be 0
+ Then the statistics counter xfrreqdone for the zone example.org. should be 0
+
+ When I query statistics socket of bind10 module Xfrout with cmdctl port 47804
+ Then the statistics counter open should be 1
+ Then the statistics counter openfail should be 0
+ Then the statistics counter close should be 0
+ Then the statistics counter bindfail should be 0
+ Then the statistics counter acceptfail should be 0
+ Then the statistics counter accept should be 0
+ Then the statistics counter senderr should be 0
+ Then the statistics counter recverr should be 0
More information about the bind10-changes
mailing list