Browse Source

Merge branch 'trac2300'

Conflicts:
	src/bin/xfrin/b10-xfrin.xml
	src/bin/xfrin/xfrin.spec
	tests/lettuce/features/xfrin_notify_handling.feature
Mukund Sivaraman 11 years ago
parent
commit
4655c110af

+ 82 - 0
src/bin/xfrin/b10-xfrin.xml

@@ -358,6 +358,88 @@ operation
         </simpara></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term>socket</term>
+        <listitem><simpara>
+          A directory name of socket statistics
+          </simpara>
+          <variablelist>
+
+            <varlistentry>
+              <term><replaceable>ipversion</replaceable></term>
+              <listitem><simpara>
+                A directory name of an IP version as ipv4 or ipv6
+                </simpara>
+                <variablelist>
+
+                  <varlistentry>
+                    <term>tcp</term>
+                    <listitem><simpara>
+                      A directory name of TCP statistics
+                      </simpara>
+                      <variablelist>
+
+                        <varlistentry>
+                          <term>open</term>
+                          <listitem><simpara>
+                           IPv4 or IPv6 TCP sockets opened successfully
+                          </simpara></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                          <term>openfail</term>
+                          <listitem><simpara>
+                           IPv4 or IPv6 TCP sockets open failures
+                          </simpara></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                          <term>close</term>
+                          <listitem><simpara>
+                           IPv4 or IPv6 TCP sockets closed
+                          </simpara></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                          <term>connfail</term>
+                          <listitem><simpara>
+                           IPv4 or IPv6 TCP sockets connection failures
+                          </simpara></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                          <term>conn</term>
+                          <listitem><simpara>
+                           IPv4 or IPv6 TCP connections established successfully
+                          </simpara></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                          <term>senderr</term>
+                          <listitem><simpara>
+                           IPv4 or IPv6 TCP sockets send errors
+                          </simpara></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                          <term>recverr</term>
+                          <listitem><simpara>
+                           IPv4 or IPv6 TCP sockets receive errors
+                          </simpara></listitem>
+                        </varlistentry>
+
+                      </variablelist>
+                    </listitem>
+                  </varlistentry><!-- end of tcp -->
+
+                </variablelist>
+              </listitem>
+            </varlistentry><!-- end of ipv4 | ipv6 -->
+
+          </variablelist>
+        </listitem>
+      </varlistentry><!-- end of socket -->
+
     </variablelist>
 
     <para>

+ 119 - 2
src/bin/xfrin/tests/xfrin_test.py

@@ -1105,12 +1105,10 @@ class TestAXFR(TestXfrinConnection):
         for (info, ver) in addrs:
             c = MockXfrinConnection({}, TEST_ZONE_NAME, RRClass.CH, None,
                                     threading.Event(), info)
-            c.init_socket()
             if ver is not None:
                 self.assertEqual(ver, c._get_ipver_str())
             else:
                 self.assertRaises(ValueError, c._get_ipver_str)
-            c.close()
 
     def test_soacheck(self):
         # we need to defer the creation until we know the QID, which is
@@ -3497,6 +3495,125 @@ class TestXfrinTransferStats(unittest.TestCase):
         zbps = self.stats.get_bytes_per_second()
         self.assertEqual(0, zbps)
 
+class TestXfrinConnectionSocketCounter(unittest.TestCase):
+
+    @property
+    def _master_addrinfo(self):
+        return TEST_MASTER_IPV4_ADDRINFO
+    @property
+    def _ipver(self):
+        return 'ipv4'
+
+    def setUp(self):
+        self.conn = XfrinConnection(
+            None, TEST_ZONE_NAME, None, MockDataSourceClient(), None,
+            self._master_addrinfo, None,
+            xfrin.Counters(xfrin.SPECFILE_LOCATION))
+        self.expception = socket.error
+
+    def raise_expception(self, *args):
+        raise self.expception
+
+    def test_open(self):
+        self.assertRaises(isc.cc.data.DataNotFoundError,
+                          self.conn._counters.get,
+                          'socket', self._ipver, 'tcp', 'open')
+        self.conn.create_socket(self._master_addrinfo[0],
+                                self._master_addrinfo[1])
+        self.assertEqual(1, self.conn._counters.get(
+                'socket', self._ipver, 'tcp', 'open'))
+
+    def test_openfail(self):
+        self.assertRaises(isc.cc.data.DataNotFoundError,
+                          self.conn._counters.get,
+                          'socket', self._ipver, 'tcp', 'openfail')
+        orig_create_socket = xfrin.asyncore.dispatcher.create_socket
+        xfrin.asyncore.dispatcher.create_socket = self.raise_expception
+        try:
+            self.assertRaises(self.expception, self.conn.create_socket,
+                              self._master_addrinfo[0],
+                              self._master_addrinfo[1])
+            self.assertEqual(1, self.conn._counters.get(
+                    'socket', self._ipver, 'tcp', 'openfail'))
+        finally:
+            xfrin.asyncore.dispatcher.create_socket = orig_create_socket
+
+    def test_close(self):
+        self.assertRaises(isc.cc.data.DataNotFoundError,
+                          self.conn._counters.get,
+                          'socket', self._ipver, 'tcp', 'close')
+        orig_socket_close = xfrin.asyncore.dispatcher.close
+        xfrin.asyncore.dispatcher.close = lambda x: None
+        try:
+            self.conn.close()
+            self.assertEqual(1, self.conn._counters.get(
+                    'socket', self._ipver, 'tcp', 'close'))
+        finally:
+            xfrin.asyncore.dispatcher.close = orig_socket_close
+
+    def test_conn(self):
+        self.assertRaises(isc.cc.data.DataNotFoundError,
+                          self.conn._counters.get,
+                          'socket', self._ipver, 'tcp', 'conn')
+        orig_socket_connect = xfrin.asyncore.dispatcher.connect
+        xfrin.asyncore.dispatcher.connect = lambda *a: None
+        try:
+            self.conn.connect(self._master_addrinfo[2])
+            self.assertEqual(1, self.conn._counters.get(
+                    'socket', self._ipver, 'tcp', 'conn'))
+        finally:
+            xfrin.asyncore.dispatcher.connect = orig_socket_connect
+
+    def test_connfail(self):
+        self.assertRaises(isc.cc.data.DataNotFoundError,
+                          self.conn._counters.get,
+                          'socket', self._ipver, 'tcp', 'connfail')
+        orig_socket_connect = xfrin.asyncore.dispatcher.connect
+        xfrin.asyncore.dispatcher.connect = self.raise_expception
+        try:
+            self.assertRaises(self.expception, self.conn.connect,
+                              self._master_addrinfo[2])
+            self.assertFalse(self.conn.connect_to_master())
+            self.assertEqual(2, self.conn._counters.get(
+                    'socket', self._ipver, 'tcp', 'connfail'))
+        finally:
+            xfrin.asyncore.dispatcher.connect = orig_socket_connect
+
+    def test_senderr(self):
+        self.assertRaises(isc.cc.data.DataNotFoundError,
+                          self.conn._counters.get,
+                          'socket', self._ipver, 'tcp', 'senderr')
+        orig_socket_send = xfrin.asyncore.dispatcher.send
+        xfrin.asyncore.dispatcher.send = self.raise_expception
+        try:
+            self.assertRaises(self.expception, self.conn.send, None)
+            self.assertEqual(1, self.conn._counters.get(
+                    'socket', self._ipver, 'tcp', 'senderr'))
+        finally:
+            xfrin.asyncore.dispatcher.send = orig_socket_send
+
+    def test_recverr(self):
+        self.assertRaises(isc.cc.data.DataNotFoundError,
+                          self.conn._counters.get,
+                          'socket', self._ipver, 'tcp', 'recverr')
+        orig_socket_recv = xfrin.asyncore.dispatcher.recv
+        xfrin.asyncore.dispatcher.recv = self.raise_expception
+        try:
+            self.assertRaises(self.expception, self.conn.recv, None)
+            self.assertEqual(1, self.conn._counters.get(
+                    'socket', self._ipver, 'tcp', 'recverr'))
+        finally:
+            xfrin.asyncore.dispatcher.recv = orig_socket_recv
+
+class TestXfrinConnectionSocketCounterV6(TestXfrinConnectionSocketCounter):
+
+    @property
+    def _master_addrinfo(self):
+        return TEST_MASTER_IPV6_ADDRINFO
+    @property
+    def _ipver(self):
+        return 'ipv6'
+
 if __name__== "__main__":
     try:
         isc.log.resetUnitTestRootLogger()

+ 75 - 2
src/bin/xfrin/xfrin.py.in

@@ -611,6 +611,11 @@ class XfrinConnection(asyncore.dispatcher):
         self._shutdown_event = shutdown_event
         self._master_addrinfo = master_addrinfo
         self._tsig_key = tsig_key
+        # self.tsig_key_name is used for outputting an error massage in
+        # connect_to_master().
+        self.tsig_key_name = None
+        if tsig_key:
+            self.tsig_key_name = self._tsig_key.get_key_name()
         self._tsig_ctx = None
         # tsig_ctx_creator is introduced to allow tests to use a mock class for
         # easier tests (in normal case we always use the default)
@@ -621,6 +626,74 @@ class XfrinConnection(asyncore.dispatcher):
         self._transfer_stats = XfrinTransferStats()
         self._counters = counters
 
+    def create_socket(self, family, type):
+        """create_socket() overridden from the super class for
+        statistics counter open and openfail"""
+        try:
+            ret = super().create_socket(family, type)
+            # count open
+            self._counters.inc('socket',
+                               'ip' + self._get_ipver_str(),
+                               'tcp', 'open')
+            return ret
+        except:
+            # count openfail
+            self._counters.inc('socket',
+                               'ip' + self._get_ipver_str(),
+                               'tcp', 'openfail')
+            raise
+
+    def close(self):
+        """close() overridden from the super class for
+        statistics counter close"""
+        ret = super().close()
+        # count close
+        self._counters.inc('socket',
+                           'ip' + self._get_ipver_str(),
+                           'tcp', 'close')
+        return ret
+
+    def connect(self, address):
+        """connect() overridden from the super class for
+        statistics counter conn and connfail"""
+        try:
+            ret = super().connect(address)
+            # count conn
+            self._counters.inc('socket',
+                               'ip' + self._get_ipver_str(),
+                               'tcp', 'conn')
+            return ret
+        except:
+            # count connfail
+            self._counters.inc('socket',
+                               'ip' + self._get_ipver_str(),
+                               'tcp', 'connfail')
+            raise
+
+    def send(self, data):
+        """send() overridden from the super class for
+        statistics counter senderr"""
+        try:
+            return super().send(data)
+        except:
+            # count senderr
+            self._counters.inc('socket',
+                               'ip' + self._get_ipver_str(),
+                               'tcp', 'senderr')
+            raise
+
+    def recv(self, buffer_size):
+        """recv() overridden from the super class for
+        statistics counter senderr"""
+        try:
+            return super().recv(buffer_size)
+        except:
+            # count recverr
+            self._counters.inc('socket',
+                               'ip' + self._get_ipver_str(),
+                               'tcp', 'recverr')
+            raise
+
     def init_socket(self):
         '''Initialize the underlyig socket.
 
@@ -861,9 +934,9 @@ class XfrinConnection(asyncore.dispatcher):
         It raises a ValueError exception on other address families.
 
         """
-        if self.socket.family == socket.AF_INET:
+        if self._master_addrinfo[0] == socket.AF_INET:
             return 'v4'
-        elif self.socket.family == socket.AF_INET6:
+        elif self._master_addrinfo[0] == socket.AF_INET6:
             return 'v6'
         raise ValueError("Invalid address family. "
                          "This is supported only for IP sockets")

+ 221 - 0
src/bin/xfrin/xfrin.spec

@@ -274,6 +274,227 @@
         "item_default": 0,
         "item_title": "SOA queries",
         "item_description": "Number of SOA queries in progress"
+      },
+      {
+        "item_name": "socket",
+        "item_type": "map",
+        "item_optional": false,
+        "item_default": {
+          "ipv4": {
+            "tcp": {
+              "open": 0,
+              "openfail": 0,
+              "close": 0,
+              "connfail": 0,
+              "conn": 0,
+              "senderr": 0,
+              "recverr": 0
+            }
+          },
+          "ipv6": {
+            "tcp": {
+              "open": 0,
+              "openfail": 0,
+              "close": 0,
+              "connfail": 0,
+              "conn": 0,
+              "senderr": 0,
+              "recverr": 0
+            }
+          }
+        },
+        "item_title": "Socket",
+        "item_description": "A directory name of socket statistics",
+        "map_item_spec": [
+          {
+            "item_name": "ipv4",
+            "item_type": "map",
+            "item_optional": false,
+            "item_default": {
+              "tcp": {
+                "open": 0,
+                "openfail": 0,
+                "close": 0,
+                "connfail": 0,
+                "conn": 0,
+                "senderr": 0,
+                "recverr": 0
+              }
+            },
+            "item_title": "IPv4",
+            "item_description": "A directory name of IPv4",
+            "map_item_spec": [
+              {
+                "item_name": "tcp",
+                "item_type": "map",
+                "item_optional": false,
+                "item_default": {
+                  "open": 0,
+                  "openfail": 0,
+                  "close": 0,
+                  "connfail": 0,
+                  "conn": 0,
+                  "senderr": 0,
+                  "recverr": 0
+                },
+                "item_title": "TCP",
+                "item_description": "A directory name of TCP statistics",
+                "map_item_spec": [
+                  {
+                    "item_name": "open",
+                    "item_type": "integer",
+                    "item_optional": false,
+                    "item_default": 0,
+                    "item_title": "Open",
+                    "item_description": "IPv4 TCP sockets opened successfully"
+                  },
+                  {
+                    "item_name": "openfail",
+                    "item_type": "integer",
+                    "item_optional": false,
+                    "item_default": 0,
+                    "item_title": "Open failures",
+                    "item_description": "IPv4 TCP sockets open failures"
+                  },
+                  {
+                    "item_name": "close",
+                    "item_type": "integer",
+                    "item_optional": false,
+                    "item_default": 0,
+                    "item_title": "Close",
+                    "item_description": "IPv4 TCP sockets closed"
+                  },
+                  {
+                    "item_name": "connfail",
+                    "item_type": "integer",
+                    "item_optional": false,
+                    "item_default": 0,
+                    "item_title": "Connect failures",
+                    "item_description": "IPv4 TCP sockets connection failures"
+                  },
+                  {
+                    "item_name": "conn",
+                    "item_type": "integer",
+                    "item_optional": false,
+                    "item_default": 0,
+                    "item_title": "Connect",
+                    "item_description": "IPv4 TCP connections established successfully"
+                  },
+                  {
+                    "item_name": "senderr",
+                    "item_type": "integer",
+                    "item_optional": false,
+                    "item_default": 0,
+                    "item_title": "Send errors",
+                    "item_description": "IPv4 TCP sockets send errors"
+                  },
+                  {
+                    "item_name": "recverr",
+                    "item_type": "integer",
+                    "item_optional": false,
+                    "item_default": 0,
+                    "item_title": "Receive errors",
+                    "item_description": "IPv4 TCP sockets receive errors"
+                  }
+                ]
+              }
+            ]
+          },
+          {
+            "item_name": "ipv6",
+            "item_type": "map",
+            "item_optional": false,
+            "item_default": {
+              "tcp": {
+                "open": 0,
+                "openfail": 0,
+                "close": 0,
+                "connfail": 0,
+                "conn": 0,
+                "senderr": 0,
+                "recverr": 0
+              }
+            },
+            "item_title": "IPv6",
+            "item_description": "A directory name of IPv6",
+            "map_item_spec": [
+              {
+                "item_name": "tcp",
+                "item_type": "map",
+                "item_optional": false,
+                "item_default": {
+                  "open": 0,
+                  "openfail": 0,
+                  "close": 0,
+                  "connfail": 0,
+                  "conn": 0,
+                  "senderr": 0,
+                  "recverr": 0
+                },
+                "item_title": "TCP",
+                "item_description": "A directory name of TCP statistics",
+                "map_item_spec": [
+                  {
+                    "item_name": "open",
+                    "item_type": "integer",
+                    "item_optional": false,
+                    "item_default": 0,
+                    "item_title": "Open",
+                    "item_description": "IPv6 TCP sockets opened successfully"
+                  },
+                  {
+                    "item_name": "openfail",
+                    "item_type": "integer",
+                    "item_optional": false,
+                    "item_default": 0,
+                    "item_title": "Open failures",
+                    "item_description": "IPv6 TCP sockets open failures"
+                  },
+                  {
+                    "item_name": "close",
+                    "item_type": "integer",
+                    "item_optional": false,
+                    "item_default": 0,
+                    "item_title": "Close",
+                    "item_description": "IPv6 TCP sockets closed"
+                  },
+                  {
+                    "item_name": "connfail",
+                    "item_type": "integer",
+                    "item_optional": false,
+                    "item_default": 0,
+                    "item_title": "Connect failures",
+                    "item_description": "IPv6 TCP sockets connection failures"
+                  },
+                  {
+                    "item_name": "conn",
+                    "item_type": "integer",
+                    "item_optional": false,
+                    "item_default": 0,
+                    "item_title": "Connect",
+                    "item_description": "IPv6 TCP connections established successfully"
+                  },
+                  {
+                    "item_name": "senderr",
+                    "item_type": "integer",
+                    "item_optional": false,
+                    "item_default": 0,
+                    "item_title": "Send errors",
+                    "item_description": "IPv6 TCP sockets send errors"
+                  },
+                  {
+                    "item_name": "recverr",
+                    "item_type": "integer",
+                    "item_optional": false,
+                    "item_default": 0,
+                    "item_title": "Receive errors",
+                    "item_description": "IPv6 TCP sockets receive errors"
+                  }
+                ]
+              }
+            ]
+          }
+        ]
       }
     ]
   }

+ 59 - 0
tests/lettuce/features/xfrin_notify_handling.feature

@@ -118,6 +118,10 @@ Feature: Xfrin incoming notify handling
       | zones.IN.example.org..last_axfr_duration |            |       0.0 |
       | soa_in_progress                          |          0 |           |
       | axfr_running                             |          0 |           |
+      | socket.ipv6.tcp.open                     |            |         1 |
+      | socket.ipv6.tcp.close                    |            |         1 |
+      | socket.ipv6.tcp.conn                     |            |         1 |
+      | socket.ipv6.tcp.connfail                 |          0 |           |
 
     #
     # Test for handling incoming notify only in IPv4
@@ -226,6 +230,10 @@ Feature: Xfrin incoming notify handling
       | zones.IN.example.org..last_axfr_duration |            |       0.0 |
       | soa_in_progress                          |          0 |           |
       | axfr_running                             |          0 |           |
+      | socket.ipv4.tcp.open                     |            |         1 |
+      | socket.ipv4.tcp.close                    |            |         1 |
+      | socket.ipv4.tcp.conn                     |            |         1 |
+      | socket.ipv4.tcp.connfail                 |          0 |           |
 
     #
     # Test for Xfr request rejected
@@ -338,6 +346,10 @@ Feature: Xfrin incoming notify handling
       | zones.IN.example.org..xfrfail   |            |         1 |
       | soa_in_progress                 |            |         0 |
       | axfr_running                    |            |         0 |
+      | socket.ipv6.tcp.open            |            |         1 |
+      | socket.ipv6.tcp.close           |            |         1 |
+      | socket.ipv6.tcp.conn            |            |         1 |
+      | socket.ipv6.tcp.connfail        |          0 |           |
 
     #
     # Test for Xfr request rejected in IPv4
@@ -450,6 +462,10 @@ Feature: Xfrin incoming notify handling
       | zones.IN.example.org..xfrfail   |            |         1 |
       | soa_in_progress                 |            |         0 |
       | axfr_running                    |            |         0 |
+      | socket.ipv4.tcp.open            |            |         1 |
+      | socket.ipv4.tcp.close           |            |         1 |
+      | socket.ipv4.tcp.conn            |            |         1 |
+      | socket.ipv4.tcp.connfail        |          0 |           |
 
     #
     # Test for unreachable slave
@@ -613,3 +629,46 @@ Feature: Xfrin incoming notify handling
     Then wait for master stderr message NOTIFY_OUT_TIMEOUT not NOTIFY_OUT_REPLY_RECEIVED
 
     A query for www.example.org to [::1]:47806 should have rcode NXDOMAIN
+
+    #
+    # Test for unreachable master
+    #
+    Scenario: Handle incoming notify (unreachable master)
+
+    And I have bind10 running with configuration xfrin/retransfer_slave_notify.conf
+    And wait for bind10 stderr message BIND10_STARTED_CC
+    And wait for bind10 stderr message CMDCTL_STARTED
+    And wait for bind10 stderr message AUTH_SERVER_STARTED
+    And wait for bind10 stderr message XFRIN_STARTED
+    And wait for bind10 stderr message ZONEMGR_STARTED
+
+    A query for www.example.org to [::1]:47806 should have rcode NXDOMAIN
+
+    #
+    # Test1 for Xfrin statistics
+    #
+    check initial statistics not containing example.org for Xfrin
+
+    #
+    # execute reftransfer for Xfrin
+    #
+    When I send bind10 the command Xfrin retransfer example.org IN
+    Then wait for new bind10 stderr message XFRIN_CONNECT_MASTER
+    Then wait for new bind10 stderr message ZONEMGR_RECEIVE_XFRIN_FAILED
+
+    #
+    # Test2 for Xfrin statistics
+    #
+    # check initial statistics
+    #
+
+    # wait until the last stats requesting is finished
+    wait for new bind10 stderr message STATS_SEND_STATISTICS_REQUEST
+    wait for new bind10 stderr message XFRIN_RECEIVED_COMMAND
+
+    When I query statistics socket of bind10 module Xfrin with cmdctl
+    The statistics counters are 0 in category .Xfrin.socket.ipv6.tcp except for the following items
+      | item_name | min_value |
+      | open      |         1 |
+      | close     |         1 |
+      | connfail  |         1 |