Browse Source

[2843] introduce dns.py

- DNS-specific information and behaviors are moved from counters.py.
- Xfrin/Xfrout/Notfyout use directly uses this module.
Naoki Kambe 11 years ago
parent
commit
bcaf721d44
2 changed files with 178 additions and 1 deletions
  1. 1 1
      src/lib/python/isc/statistics/Makefile.am
  2. 177 0
      src/lib/python/isc/statistics/dns.py

+ 1 - 1
src/lib/python/isc/statistics/Makefile.am

@@ -1,6 +1,6 @@
 SUBDIRS = . tests
 SUBDIRS = . tests
 
 
-python_PYTHON = __init__.py counters.py
+python_PYTHON = __init__.py counters.py dns.py
 pythondir = $(pyexecdir)/isc/statistics
 pythondir = $(pyexecdir)/isc/statistics
 
 
 CLEANDIRS = __pycache__
 CLEANDIRS = __pycache__

+ 177 - 0
src/lib/python/isc/statistics/dns.py

@@ -0,0 +1,177 @@
+# Copyright (C) 2013  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
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+"""BIND 10 statistics counters module for DNS
+
+This module basically inherits the class in isc.statistics.counters.
+It handles DNS-specific information. For a DNS purpose, each BIND 10
+module uses this module instead of the parent module
+(isc.statistics.counters). Also see isc.statistics.counters.__doc__
+for details."""
+
+import isc.config
+from isc.statistics import counters
+
+class _Statistics():
+    """Statistics data set"""
+    # default statistics data
+    _data = {}
+    # default statistics spec used in case the specfile is omitted when
+    # constructing a Counters() object
+    _spec = [
+      {
+        "item_name": "zones",
+        "item_type": "named_set",
+        "item_optional": False,
+        "item_default": {
+          "_SERVER_" : {
+            "notifyoutv4" : 0,
+            "notifyoutv6" : 0
+          }
+        },
+        "item_title": "Zone names",
+        "item_description": "Zone names",
+        "named_set_item_spec": {
+          "item_name": "classname",
+          "item_type": "named_set",
+          "item_optional": False,
+          "item_default": {},
+          "item_title": "RR class name",
+          "item_description": "RR class name",
+          "named_set_item_spec": {
+            "item_name": "zonename",
+            "item_type": "map",
+            "item_optional": False,
+            "item_default": {},
+            "item_title": "Zone name",
+            "item_description": "Zone name",
+            "map_item_spec": [
+              {
+                "item_name": "notifyoutv4",
+                "item_type": "integer",
+                "item_optional": False,
+                "item_default": 0,
+                "item_title": "IPv4 notifies",
+                "item_description": "Number of IPv4 notifies per zone name sent out"
+              },
+              {
+                "item_name": "notifyoutv6",
+                "item_type": "integer",
+                "item_optional": False,
+                "item_default": 0,
+                "item_title": "IPv6 notifies",
+                "item_description": "Number of IPv6 notifies per zone name sent out"
+              }
+            ]
+          }
+        }
+      }
+    ]
+
+class Counters(counters.Counters):
+    """A list of counters which can be handled in the class are like
+    the following. Also see counters.Counters.__doc__ for details.
+
+        zones/IN/example.com./notifyoutv4
+        zones/IN/example.com./notifyoutv6
+        zones/IN/example.com./xfrrej
+        zones/IN/example.com./xfrreqdone
+        zones/IN/example.com./soaoutv4
+        zones/IN/example.com./soaoutv6
+        zones/IN/example.com./axfrreqv4
+        zones/IN/example.com./axfrreqv6
+        zones/IN/example.com./ixfrreqv4
+        zones/IN/example.com./ixfrreqv6
+        zones/IN/example.com./xfrsuccess
+        zones/IN/example.com./xfrfail
+        zones/IN/example.com./last_ixfr_duration
+        zones/IN/example.com./last_axfr_duration
+        ixfr_running
+        axfr_running
+        socket/unixdomain/open
+        socket/unixdomain/openfail
+        socket/unixdomain/close
+        socket/unixdomain/bindfail
+        socket/unixdomain/acceptfail
+        socket/unixdomain/accept
+        socket/unixdomain/senderr
+        socket/unixdomain/recverr
+        socket/ipv4/tcp/open
+        socket/ipv4/tcp/openfail
+        socket/ipv4/tcp/close
+        socket/ipv4/tcp/connfail
+        socket/ipv4/tcp/conn
+        socket/ipv4/tcp/senderr
+        socket/ipv4/tcp/recverr
+        socket/ipv6/tcp/open
+        socket/ipv6/tcp/openfail
+        socket/ipv6/tcp/close
+        socket/ipv6/tcp/connfail
+        socket/ipv6/tcp/conn
+        socket/ipv6/tcp/senderr
+        socket/ipv6/tcp/recverr
+    """
+    # '_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'
+    # default statistics data set
+    _statistics = _Statistics()
+
+    def __init__(self, spec_file_name=None):
+        """If the spec file has 'zones', it obtains a list of counter
+        names under it when initiating.  For behaviors other than
+        this, see isc.statistics.counters.Counters.__init__.__doc__."""
+        counters.Counters.__init__(self, spec_file_name)
+        if self._perzone_prefix in \
+                isc.config.spec_name_list(self._statistics._spec):
+            self._zones_item_list = isc.config.spec_name_list(
+                isc.config.find_spec_part(
+                    self._statistics._spec,
+                    '%s/%s/%s' % (self._perzone_prefix,
+                                  '_CLASS_', self._entire_server)))
+
+    def get_statistics(self):
+        """Calculates an entire server's counts, and returns statistics
+        data in a format to send out to the stats module, including each
+        counter. If nothing is counted yet, then it returns an empty
+        dictionary."""
+        # entire copy
+        statistics_data = self._statistics._data.copy()
+        # If there is no 'zones' found in statistics_data,
+        # i.e. statistics_data contains no per-zone counter, it just
+        # returns statistics_data because calculating total counts
+        # across the zone names isn't necessary.
+        if self._perzone_prefix not in statistics_data:
+            return statistics_data
+        zones = statistics_data[self._perzone_prefix]
+        # Start calculation for '_SERVER_' counts
+        zones_spec = isc.config.find_spec_part(self._statistics._spec,
+                                               self._perzone_prefix)
+        zones_data = {}
+        for cls in zones.keys():
+            for zone in zones[cls].keys():
+                for (attr, val) in zones[cls][zone].items():
+                    id_str1 = '%s/%s/%s' % (cls, zone, attr)
+                    id_str2 = '%s/%s/%s' % (cls, self._entire_server, attr)
+                    counters._set_counter(zones_data, zones_spec, id_str1, val)
+                    counters._inc_counter(zones_data, zones_spec, id_str2, val)
+        # insert entire-server counts
+        statistics_data[self._perzone_prefix] = dict(
+            statistics_data[self._perzone_prefix],
+            **zones_data)
+        return statistics_data