Browse Source

[917] implement stats_spec2xsd function and modify the xsd template file

Naoki Kambe 13 years ago
parent
commit
cb57c9fcaa

+ 1 - 22
src/bin/stats/stats-httpd-xsd.tpl

@@ -14,25 +14,4 @@
  - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  - PERFORMANCE OF THIS SOFTWARE.
  - PERFORMANCE OF THIS SOFTWARE.
 -->
 -->
-
-<schema targetNamespace="$xsd_namespace"
-  xmlns="http://www.w3.org/2001/XMLSchema"
-  xmlns:stats="$xsd_namespace">
-  <annotation>
-    <documentation xml:lang="en">XML schema of the statistics
-      data in BIND 10</documentation>
-  </annotation>
-  <element name="stats_data">
-    <annotation>
-      <documentation>A set of statistics data</documentation>
-    </annotation>
-    <complexType>
-      $xsd_string
-      <attribute name="version" type="token" use="optional" default="1.0">
-        <annotation>
-          <documentation>Version number of syntax</documentation>
-        </annotation>
-      </attribute>
-    </complexType>
-  </element>
-</schema>
+$xsd_string

+ 143 - 78
src/bin/stats/stats_httpd.py.in

@@ -67,7 +67,7 @@ XML_URL_PATH = '/bind10/statistics/xml'
 XSD_URL_PATH = '/bind10/statistics/xsd'
 XSD_URL_PATH = '/bind10/statistics/xsd'
 XSL_URL_PATH = '/bind10/statistics/xsl'
 XSL_URL_PATH = '/bind10/statistics/xsl'
 # TODO: This should be considered later.
 # TODO: This should be considered later.
-XSD_NAMESPACE = 'http://bind10.isc.org' + XSD_URL_PATH
+XSD_NAMESPACE = 'http://bind10.isc.org/bind10'
 
 
 # Assign this process name
 # Assign this process name
 isc.util.process.rename()
 isc.util.process.rename()
@@ -387,7 +387,7 @@ class StatsHttpd:
             param['name'] = name
             param['name'] = name
         try:
         try:
             seq = self.cc_session.group_sendmsg(
             seq = self.cc_session.group_sendmsg(
-                isc.config.ccsession.create_command('showschema'), 'Stats')
+                isc.config.ccsession.create_command('showschema', param), 'Stats')
             (answer, env) = self.cc_session.group_recvmsg(False, seq)
             (answer, env) = self.cc_session.group_recvmsg(False, seq)
             if answer:
             if answer:
                 (rcode, value) = isc.config.ccsession.parse_answer(answer)
                 (rcode, value) = isc.config.ccsession.parse_answer(answer)
@@ -400,55 +400,57 @@ class StatsHttpd:
             raise StatsHttpdError("%s: %s" %
             raise StatsHttpdError("%s: %s" %
                                   (err.__class__.__name__, err))
                                   (err.__class__.__name__, err))
 
 
-    def stats_data2xml(self, stats_spec, stats_data, xml_elem):
-        """Reads stats_data and stats_spec specified as first and
-        second arguments, and modify the xml object specified as
-        fourth argument. xml_elem must be modified and always returns
-        None."""
-        # assumed started with module_spec or started with item_spec in statistics
-        if type(stats_spec) is dict:
-            # assumed started with module_spec
-            if 'item_name' not in stats_spec \
-                    and 'item_type' not in stats_spec:
-                for module_name in stats_spec.keys():
-                    elem = xml.etree.ElementTree.Element(module_name)
-                    self.stats_data2xml(stats_spec[module_name],
-                                        stats_data[module_name], elem)
-                    xml_elem.append(elem)
-            # started with item_spec in statistics
-            else:
-                if stats_spec['item_type'] == 'map':
-                    elem = xml.etree.ElementTree.Element(stats_spec['item_name'])
-                    self.stats_data2xml(stats_spec['map_item_spec'],
-                                        stats_data,
-                                        elem)
-                    xml_elem.append(elem)
-                elif stats_spec['item_type'] == 'list':
-                    elem = xml.etree.ElementTree.Element(stats_spec['item_name'])
-                    for item in stats_data:
-                        self.stats_data2xml(stats_spec['list_item_spec'],
-                                            item,
-                                            elem)
-                    xml_elem.append(elem)
-                else:
-                    elem = xml.etree.ElementTree.Element(stats_spec['item_name'])
-                    elem.text = str(stats_data)
-                    xml_elem.append(elem)
-        # assumed started with stats_spec
-        elif type(stats_spec) is list:
-            for item_spec in stats_spec:
-                #elem = xml.etree.ElementTree.Element(item_spec['item_name'])
-                self.stats_data2xml(item_spec,
-                                    stats_data[item_spec['item_name']],
-                                    xml_elem)
-                #xml_elem.append(elem)
-        else:
-            xml_elem.text = str(stats_data)
-        return None
 
 
     def xml_handler(self, module_name=None, item_name=None):
     def xml_handler(self, module_name=None, item_name=None):
         """Handler which requests to Stats daemon to obtain statistics
         """Handler which requests to Stats daemon to obtain statistics
         data and returns the body of XML document"""
         data and returns the body of XML document"""
+
+        def stats_data2xml(stats_spec, stats_data, xml_elem):
+            """Internal use for xml_handler. Reads stats_data and
+            stats_spec specified as first and second arguments, and
+            modify the xml object specified as third
+            argument. xml_elem must be modified and always returns
+            None."""
+            # assumed started with module_spec or started with
+            # item_spec in statistics
+            if type(stats_spec) is dict:
+                # assumed started with module_spec
+                if 'item_name' not in stats_spec \
+                        and 'item_type' not in stats_spec:
+                    for module_name in stats_spec.keys():
+                        elem = xml.etree.ElementTree.Element(module_name)
+                        stats_data2xml(stats_spec[module_name],
+                                            stats_data[module_name], elem)
+                        xml_elem.append(elem)
+                # started with item_spec in statistics
+                else:
+                    if stats_spec['item_type'] == 'map':
+                        elem = xml.etree.ElementTree.Element(stats_spec['item_name'])
+                        stats_data2xml(stats_spec['map_item_spec'],
+                                            stats_data,
+                                            elem)
+                        xml_elem.append(elem)
+                    elif stats_spec['item_type'] == 'list':
+                        elem = xml.etree.ElementTree.Element(stats_spec['item_name'])
+                        for item in stats_data:
+                            stats_data2xml(stats_spec['list_item_spec'],
+                                                item,
+                                                elem)
+                        xml_elem.append(elem)
+                    else:
+                        elem = xml.etree.ElementTree.Element(stats_spec['item_name'])
+                        elem.text = str(stats_data)
+                        xml_elem.append(elem)
+            # assumed started with stats_spec
+            elif type(stats_spec) is list:
+                for item_spec in stats_spec:
+                    stats_data2xml(item_spec,
+                                        stats_data[item_spec['item_name']],
+                                        xml_elem)
+            else:
+                xml_elem.text = str(stats_data)
+            return None
+
         stats_spec = self.get_stats_spec(module_name, item_name)
         stats_spec = self.get_stats_spec(module_name, item_name)
         stats_data = self.get_stats_data(module_name, item_name)
         stats_data = self.get_stats_data(module_name, item_name)
         xml_elem = xml.etree.ElementTree.Element(
         xml_elem = xml.etree.ElementTree.Element(
@@ -456,7 +458,7 @@ class StatsHttpd:
             attrib={ 'xsi:schemaLocation' : XSD_NAMESPACE + ' ' + XSD_URL_PATH,
             attrib={ 'xsi:schemaLocation' : XSD_NAMESPACE + ' ' + XSD_URL_PATH,
                      'xmlns:bind10' : XSD_NAMESPACE,
                      'xmlns:bind10' : XSD_NAMESPACE,
                      'xmlns:xsi' : "http://www.w3.org/2001/XMLSchema-instance" })
                      'xmlns:xsi' : "http://www.w3.org/2001/XMLSchema-instance" })
-        self.stats_data2xml(stats_spec, stats_data, xml_elem)
+        stats_data2xml(stats_spec, stats_data, xml_elem)
         # The coding conversion is tricky. xml..tostring() of Python 3.2
         # The coding conversion is tricky. xml..tostring() of Python 3.2
         # returns bytes (not string) regardless of the coding, while
         # returns bytes (not string) regardless of the coding, while
         # tostring() of Python 3.1 returns a string.  To support both
         # tostring() of Python 3.1 returns a string.  To support both
@@ -473,34 +475,99 @@ class StatsHttpd:
 
 
     def xsd_handler(self, module_name=None, item_name=None):
     def xsd_handler(self, module_name=None, item_name=None):
         """Handler which just returns the body of XSD document"""
         """Handler which just returns the body of XSD document"""
+
+        def stats_spec2xsd(stats_spec, xsd_elem):
+            """Internal use for xsd_handler. Reads stats_spec
+            specified as first arguments, and modify the xml object
+            specified as second argument. xsd_elem must be
+            modified. Always returns None with no exceptions."""
+            # assumed module_spec or one stats_spec
+            if type(stats_spec) is dict:
+                # assumed module_spec
+                if 'item_name' not in stats_spec:
+                        alltag = xml.etree.ElementTree.Element("all")
+                        for mod in stats_spec.keys():
+                            stats_spec2xsd(stats_spec[mod], alltag)
+                        complextype = xml.etree.ElementTree.Element("complexType")
+                        complextype.append(alltag)
+                        elem = xml.etree.ElementTree.Element(
+                            "element", { "name" : mod })
+                        elem.append(complextype)
+                        xsd_elem.append(elem)
+                # assumed stats_spec
+                else:
+                    if stats_spec['item_type'] == 'map':
+                        alltag = xml.etree.ElementTree.Element("all")
+                        stats_spec2xsd(stats_spec['map_item_spec'], alltag)
+                        complextype = xml.etree.ElementTree.Element("complexType")
+                        complextype.append(alltag)
+                        elem = xml.etree.ElementTree.Element(
+                            "element", { "name" : stats_spec["item_name"] })
+                        elem.append(complextype)
+                        xsd_elem.append(elem)
+                    elif stats_spec['item_type'] == 'list':
+                        alltag = xml.etree.ElementTree.Element("all")
+                        stats_spec2xsd(stats_spec['list_item_spec'], alltag)
+                        complextype = xml.etree.ElementTree.Element("complexType")
+                        complextype.append(alltag)
+                        elem = xml.etree.ElementTree.Element(
+                            "element", { "name" : stats_spec["item_name"] })
+                        elem.append(complextype)
+                        xsd_elem.append(elem)
+                    else:
+                        elem = xml.etree.ElementTree.Element(
+                            "element",
+                            attrib={
+                                'name' : stats_spec["item_name"],
+                                'type' : stats_spec["item_type"] \
+                                    if stats_spec["item_type"].lower() != 'real' \
+                                    else 'float',
+                                'minOccurs' : "1",
+                                'maxOccurs' : "1"
+                                }
+                            )
+                        annotation = xml.etree.ElementTree.Element("annotation")
+                        appinfo = xml.etree.ElementTree.Element("appinfo")
+                        documentation = xml.etree.ElementTree.Element("documentation")
+                        if "item_title" in stats_spec:
+                            appinfo.text = stats_spec["item_title"]
+                        if "item_description" in stats_spec:
+                            documentation.text = stats_spec["item_description"]
+                        annotation.append(appinfo)
+                        annotation.append(documentation)
+                        elem.append(annotation)
+                        xsd_elem.append(elem)
+            # multiple stats_specs
+            elif type(stats_spec) is list:
+                for item_spec in stats_spec:
+                    stats_spec2xsd(item_spec, xsd_elem)
+            return None
+
         # for XSD
         # for XSD
-        xsd_root = xml.etree.ElementTree.Element("all") # started with "all" tag
-        for (mod, spec) in self.get_stats_spec(module_name, item_name).items():
-            if not spec: continue
-            alltag = xml.etree.ElementTree.Element("all")
-            for item in spec:
-                element = xml.etree.ElementTree.Element(
-                    "element",
-                    dict( name=item["item_name"],
-                          type=item["item_type"] if item["item_type"].lower() != 'real' else 'float',
-                          minOccurs="1",
-                          maxOccurs="1" ),
-                    )
-                annotation = xml.etree.ElementTree.Element("annotation")
-                appinfo = xml.etree.ElementTree.Element("appinfo")
-                documentation = xml.etree.ElementTree.Element("documentation")
-                appinfo.text = item["item_title"]
-                documentation.text = item["item_description"]
-                annotation.append(appinfo)
-                annotation.append(documentation)
-                element.append(annotation)
-                alltag.append(element)
-
-            complextype = xml.etree.ElementTree.Element("complexType")
-            complextype.append(alltag)
-            mod_element = xml.etree.ElementTree.Element("element", { "name" : mod })
-            mod_element.append(complextype)
-            xsd_root.append(mod_element)
+        stats_spec = self.get_stats_spec(module_name, item_name)
+        alltag = xml.etree.ElementTree.Element("all")
+        stats_spec2xsd(stats_spec, alltag)
+        complextype = xml.etree.ElementTree.Element("complexType")
+        complextype.append(alltag)
+        documentation = xml.etree.ElementTree.Element("documentation")
+        documentation.text = "A set of statistics data"
+        annotation = xml.etree.ElementTree.Element("annotation")
+        annotation.append(documentation)
+        elem = xml.etree.ElementTree.Element(
+            "element", attrib={ 'name' : 'statistics' })
+        elem.append(annotation)
+        elem.append(complextype)
+        documentation = xml.etree.ElementTree.Element("documentation")
+        documentation.text = "XML schema of the statistics data in BIND 10"
+        annotation = xml.etree.ElementTree.Element("annotation")
+        annotation.append(documentation)
+        xsd_root = xml.etree.ElementTree.Element(
+            "schema",
+            attrib={ 'xmlns' : "http://www.w3.org/2001/XMLSchema",
+                     'targetNamespace' : XSD_NAMESPACE,
+                     'xmlns:bind10' : XSD_NAMESPACE })
+        xsd_root.append(annotation)
+        xsd_root.append(elem)
         # The coding conversion is tricky. xml..tostring() of Python 3.2
         # The coding conversion is tricky. xml..tostring() of Python 3.2
         # returns bytes (not string) regardless of the coding, while
         # returns bytes (not string) regardless of the coding, while
         # tostring() of Python 3.1 returns a string.  To support both
         # tostring() of Python 3.1 returns a string.  To support both
@@ -510,9 +577,7 @@ class StatsHttpd:
         xsd_string = str(xml.etree.ElementTree.tostring(xsd_root, encoding='utf-8'),
         xsd_string = str(xml.etree.ElementTree.tostring(xsd_root, encoding='utf-8'),
                          encoding='us-ascii')
                          encoding='us-ascii')
         self.xsd_body = self.open_template(XSD_TEMPLATE_LOCATION).substitute(
         self.xsd_body = self.open_template(XSD_TEMPLATE_LOCATION).substitute(
-            xsd_string=xsd_string,
-            xsd_namespace=XSD_NAMESPACE
-            )
+            xsd_string=xsd_string)
         assert self.xsd_body is not None
         assert self.xsd_body is not None
         return self.xsd_body
         return self.xsd_body
 
 

+ 0 - 1
src/bin/stats/tests/Makefile.am

@@ -1,6 +1,5 @@
 PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
 PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
 PYTESTS = b10-stats_test.py b10-stats-httpd_test.py
 PYTESTS = b10-stats_test.py b10-stats-httpd_test.py
-PYTESTS = b10-stats-httpd_test.py
 EXTRA_DIST = $(PYTESTS) test_utils.py
 EXTRA_DIST = $(PYTESTS) test_utils.py
 CLEANFILES = test_utils.pyc msgq_socket_test
 CLEANFILES = test_utils.pyc msgq_socket_test
 
 

File diff suppressed because it is too large
+ 117 - 74
src/bin/stats/tests/b10-stats-httpd_test.py