BIND 10 trac2053, updated. 1fc2b06b57a008ec602daa2dac79939b3cc6b65d Merge branch 'master' into trac2053

BIND 10 source code commits bind10-changes at lists.isc.org
Thu Jul 5 06:42:13 UTC 2012


The branch, trac2053 has been updated
       via  1fc2b06b57a008ec602daa2dac79939b3cc6b65d (commit)
       via  d5ec81ad8f86f860c2b8e5c9980268da2efdd94e (commit)
       via  cdada0b63865c20370d42715df72d90f8e59e8bb (commit)
       via  4b90f2ac3b8de3f1a61d7b5f743f2721c6dd34b3 (commit)
       via  144e80212746f8d55e6a59edcf689fec9f32ae95 (commit)
       via  a64cb609ee3d2004212634685dc8a9cae46ea617 (commit)
       via  e26eb608b1feb0dcd764a1efa1dd89561b651e19 (commit)
       via  1170780af08a0de33e882da5409776fe0e7f2a11 (commit)
       via  304e2b97b852eeaee4d6be57d54dc30a413dbbd1 (commit)
       via  c7017fc5e4fb0ec1b7b3fa84f96e91d68e0a46f2 (commit)
       via  fdc9afcf5e90f2d6cacf9da65cb8ab1d7e515fd0 (commit)
       via  83e396404b5f484f1d2462664948ee6031abe638 (commit)
       via  99d2c13f8d73b423fde8e557f8775e4c24ca6d03 (commit)
       via  dbef0e25199a8694e57e03fba704d5aa839ab3b7 (commit)
       via  6b32945256d568825b2c0c07fd84d96efedd85bf (commit)
       via  87e091a226590e11fea99cc16af4c03a25f0b840 (commit)
       via  7e93a92e0d3f54263bd0d72cbdcb06c30229ac1f (commit)
       via  9dfb07c8ce80f1082f1d493705d95ece544dd1ca (commit)
       via  f4e22ffd7bfb3ffbc024d801f3c6dbb7312261ec (commit)
       via  1a0fc96ac4cf6f324631e67ac391b85d6eec5b08 (commit)
       via  c6385a4f54979296a9eb50da73d9fccddff81ff6 (commit)
       via  bed40730d9387775ad655427420157d6d18b33b1 (commit)
       via  04fd11bf0539ea3ace1c103cf4488cb965aec659 (commit)
       via  5c6c47046be1da96c581693c500461dff5ba9304 (commit)
       via  c09a49cd3d1cd3498a7c7fb778abbe5485989e65 (commit)
       via  491a0e2f9cd8a8c72bd9ae5c1650e523ca8afab9 (commit)
       via  02f0aa67d53e253855814e88e885cf19e6dfdf96 (commit)
       via  6276f4098c51d0f8b8703aa3a6cbf56f07264959 (commit)
       via  18bcce8781a3b410b0d6f8712495da27a28b9fc5 (commit)
       via  b2a7049b19584687962588cd5695748541ddfc32 (commit)
       via  86b50d54a6e3eac0275314ddeb77eb8ad5fbab73 (commit)
       via  57c61f2f457ac99686706d05dda5cd39737c6bd0 (commit)
      from  9771dfb067dc0bf250d69bc4c07c811573d2c656 (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 1fc2b06b57a008ec602daa2dac79939b3cc6b65d
Merge: 9771dfb d5ec81a
Author: Mukund Sivaraman <muks at isc.org>
Date:   Thu Jul 5 11:15:10 2012 +0530

    Merge branch 'master' into trac2053

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog                                          |    6 +
 configure.ac                                       |    4 +
 doc/guide/bind10-guide.xml                         |   31 +--
 src/bin/Makefile.am                                |    3 +-
 src/bin/cmdctl/cmdctl.py.in                        |    2 +-
 src/bin/showtech/.gitignore                        |    2 +
 src/bin/showtech/Makefile.am                       |   28 ++
 .../{dhcp4/b10-dhcp4.8 => showtech/b10-showtech.1} |   38 +--
 .../b10-dhcp4.xml => showtech/b10-showtech.xml}    |   48 ++--
 src/bin/showtech/showtech.py.in                    |  127 +++++++++
 src/lib/config/tests/ccsession_unittests.cc        |   11 +-
 src/lib/datasrc/rbtree.h                           |    3 +
 src/lib/dns/labelsequence.cc                       |   15 +
 src/lib/dns/labelsequence.h                        |   16 +-
 src/lib/dns/name.cc                                |   56 +++-
 src/lib/dns/name.h                                 |   33 ++-
 src/lib/dns/tests/labelsequence_unittest.cc        |  217 +++++++++++++++
 src/lib/python/isc/Makefile.am                     |    2 +-
 src/lib/python/isc/{dns => sysinfo}/Makefile.am    |    7 +-
 src/lib/python/isc/sysinfo/__init__.py             |    1 +
 src/lib/python/isc/sysinfo/sysinfo.py              |  286 ++++++++++++++++++++
 .../python/isc/{ddns => sysinfo}/tests/Makefile.am |    9 +-
 src/lib/python/isc/sysinfo/tests/sysinfo_test.py   |  197 ++++++++++++++
 23 files changed, 1061 insertions(+), 81 deletions(-)
 create mode 100644 src/bin/showtech/.gitignore
 create mode 100644 src/bin/showtech/Makefile.am
 copy src/bin/{dhcp4/b10-dhcp4.8 => showtech/b10-showtech.1} (57%)
 copy src/bin/{dhcp4/b10-dhcp4.xml => showtech/b10-showtech.xml} (60%)
 create mode 100755 src/bin/showtech/showtech.py.in
 copy src/lib/python/isc/{dns => sysinfo}/Makefile.am (51%)
 create mode 100644 src/lib/python/isc/sysinfo/__init__.py
 create mode 100644 src/lib/python/isc/sysinfo/sysinfo.py
 copy src/lib/python/isc/{ddns => sysinfo}/tests/Makefile.am (73%)
 create mode 100644 src/lib/python/isc/sysinfo/tests/sysinfo_test.py

-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index 8af8299..fa85446 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+452.	[func]*		muks
+	b10-showtech: An initial implementation of the b10-showtech tool
+	is now available. It gathers and outputs system information which
+	can be used by future tech support staff.
+	(Trac #2062, git 144e80212746f8d55e6a59edcf689fec9f32ae95)
+
 451.	[bug]		muks, jinmei
 	libdatasrc: the database-based data source now correctly returns
 	glue records on (not under) a zone cut, such as in the case where
diff --git a/configure.ac b/configure.ac
index 70df25d..3fdb6fb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1027,6 +1027,7 @@ AC_CONFIG_FILES([Makefile
                  src/bin/dhcp4/tests/Makefile
                  src/bin/resolver/Makefile
                  src/bin/resolver/tests/Makefile
+                 src/bin/showtech/Makefile
                  src/bin/sockcreator/Makefile
                  src/bin/sockcreator/tests/Makefile
                  src/bin/xfrin/Makefile
@@ -1082,6 +1083,8 @@ AC_CONFIG_FILES([Makefile
                  src/lib/python/isc/xfrin/tests/Makefile
                  src/lib/python/isc/server_common/Makefile
                  src/lib/python/isc/server_common/tests/Makefile
+                 src/lib/python/isc/sysinfo/Makefile
+                 src/lib/python/isc/sysinfo/tests/Makefile
                  src/lib/config/Makefile
                  src/lib/config/tests/Makefile
                  src/lib/config/tests/testdata/Makefile
@@ -1159,6 +1162,7 @@ AC_OUTPUT([doc/version.ent
            src/bin/zonemgr/zonemgr.spec.pre
            src/bin/zonemgr/tests/zonemgr_test
            src/bin/zonemgr/run_b10-zonemgr.sh
+           src/bin/showtech/showtech.py
            src/bin/stats/stats.py
            src/bin/stats/stats_httpd.py
            src/bin/bind10/bind10_src.py
diff --git a/doc/guide/bind10-guide.xml b/doc/guide/bind10-guide.xml
index 5689b9a..c2e5186 100644
--- a/doc/guide/bind10-guide.xml
+++ b/doc/guide/bind10-guide.xml
@@ -92,7 +92,7 @@
       <title>Supported Platforms</title>
       <para>
   BIND 10 builds have been tested on (in no particular order)
-  Debian GNU/Linux 5 and unstable, Ubuntu 9.10, NetBSD 5,
+  Debian GNU/Linux 6 and unstable, Ubuntu 9.10, NetBSD 5,
   Solaris 10 and 11, FreeBSD 7 and 8, CentOS Linux 5.3,
   MacOS 10.6 and 10.7, and OpenBSD 5.1.
 
@@ -105,7 +105,17 @@
     </section>
 
     <section id="required-software">
-      <title>Required Software</title>
+      <title>Required Software at Run-time</title>
+
+      <para>
+        Running BIND 10 uses various extra software which may
+        not be provided in some operating systems' default
+        installations nor standard packages collections. You may
+        need to install this required software separately.
+        (For the build requirements, also see
+        <xref linkend="build-requirements"/>.)
+      </para>
+
       <para>
         BIND 10 requires at least Python 3.1
         (<ulink url="http://www.python.org/"/>).
@@ -140,15 +150,6 @@
         Python modules need to be built for the corresponding Python 3.
       </para>
 <!-- TODO: this will change ... -->
-
-      <note>
-        <para>
-          Some operating systems do not provide these dependencies
-          in their default installation nor standard packages
-          collections.
-          You may need to install them separately.
-        </para>
-      </note>
     </section>
 
     <section id="starting_stopping">
@@ -1058,9 +1059,6 @@ address, but the usual ones don't." mean? -->
         specifications and all current settings to the
         <command>bindctl</command> client (via
         <command>b10-cmdctl</command>).
-      </para>
-
-      <para>
         <command>b10-cfgmgr</command> relays configurations received
         from <command>b10-cmdctl</command> to the appropriate modules.
       </para>
@@ -1079,7 +1077,7 @@ config changes are actually commands to cfgmgr
       <para>
         The stored configuration file is at
         <filename>/usr/local/var/bind10-devel/b10-config.db</filename>.
-        (The full path is what was defined at build configure time for
+        (The directory is what was defined at build configure time for
         <option>--localstatedir</option>.
         The default is <filename>/usr/local/var/</filename>.)
         The format is loosely based on JSON and is directly parseable
@@ -1197,7 +1195,7 @@ but you might wanna check with likun
 
 <!-- TODO
 openssl req -new -x509 -keyout server.pem -out server.pem -days 365 -nodes
-but that is a single file, maybethis should go back to that format?
+but that is a single file, maybe this should go back to that format?
 -->
 
 <!--
@@ -1264,7 +1262,6 @@ shutdown
 <!--
 TODO
 (12:21:30) jinmei: I'd like to have sample session using a command line www client such as wget
-(12:21:33) jinmei: btw
 -->
 
   </chapter>
diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am
index 499e209..c821b9f 100644
--- a/src/bin/Makefile.am
+++ b/src/bin/Makefile.am
@@ -1,4 +1,5 @@
 SUBDIRS = bind10 bindctl cfgmgr ddns loadzone msgq host cmdctl auth xfrin \
-	xfrout usermgr zonemgr stats tests resolver sockcreator dhcp4 dhcp6 dbutil
+	xfrout usermgr zonemgr stats tests resolver sockcreator dhcp4 dhcp6 \
+	dbutil showtech
 
 check-recursive: all-recursive
diff --git a/src/bin/cmdctl/cmdctl.py.in b/src/bin/cmdctl/cmdctl.py.in
index 74fc364..4076f4c 100755
--- a/src/bin/cmdctl/cmdctl.py.in
+++ b/src/bin/cmdctl/cmdctl.py.in
@@ -541,7 +541,7 @@ class SecureHTTPServer(socketserver_mixin.NoPollMixIn,
                                       ssl_version = ssl.PROTOCOL_SSLv23)
             return ssl_sock
         except (ssl.SSLError, CmdctlException) as err :
-            logger.info(CMDCTL_SSL_SETUP_FAILURE_USER_DENIED, err)
+            logger.error(CMDCTL_SSL_SETUP_FAILURE_USER_DENIED, err)
             self.close_request(sock)
             # raise socket error to finish the request
             raise socket.error
diff --git a/src/bin/showtech/.gitignore b/src/bin/showtech/.gitignore
new file mode 100644
index 0000000..f3d5873
--- /dev/null
+++ b/src/bin/showtech/.gitignore
@@ -0,0 +1,2 @@
+/b10-showtech
+/showtech.py
diff --git a/src/bin/showtech/Makefile.am b/src/bin/showtech/Makefile.am
new file mode 100644
index 0000000..cc9923c
--- /dev/null
+++ b/src/bin/showtech/Makefile.am
@@ -0,0 +1,28 @@
+bin_SCRIPTS = b10-showtech
+
+CLEANFILES = b10-showtech showtech.pyc
+
+# this is done here since configure.ac AC_OUTPUT doesn't expand exec_prefix
+b10-showtech: showtech.py
+	$(SED) -e "s|@@PYTHONPATH@@|@pyexecdir@|" showtech.py >$@
+	chmod a+x $@
+
+MAN1_FILES = \
+	b10-showtech.xml
+
+man_MANS = \
+	$(MAN1_FILES:.xml=.1)
+
+if ENABLE_MAN
+
+.xml.1:
+	xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $<
+
+endif
+
+EXTRA_DIST = $(man_MANS) $(MAN1_FILES)
+
+CLEANDIRS = __pycache__
+
+clean-local:
+	rm -rf $(CLEANDIRS)
diff --git a/src/bin/showtech/b10-showtech.1 b/src/bin/showtech/b10-showtech.1
new file mode 100644
index 0000000..b331713
--- /dev/null
+++ b/src/bin/showtech/b10-showtech.1
@@ -0,0 +1,66 @@
+'\" t
+.\"     Title: b10-showtech
+.\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.76.1 <http://docbook.sf.net/>
+.\"      Date: June 26, 2012
+.\"    Manual: BIND10
+.\"    Source: BIND10
+.\"  Language: English
+.\"
+.TH "B10\-SHOWTECH" "1" "June 26, 2012" "BIND10" "BIND10"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+b10-showtech \- BIND 10 system information display tool
+.SH "SYNOPSIS"
+.HP \w'\fBb10\-showtech\fR\ 'u
+\fBb10\-showtech\fR
+.SH "DESCRIPTION"
+.PP
+The
+\fBb10\-showtech\fR
+program collects and outputs a variety of information about the system that BIND 10 is running on\&. This information can be useful to people involved in debugging and technical support\&.
+.SH "ARGUMENTS"
+.PP
+\-h
+.RS 4
+Displays usage instructions\&.
+.RE
+.PP
+\-o \fIoutput\-file\fR
+.RS 4
+If an output file is specified, the output of
+\fBb10\-showtech\fR
+is written to this file\&. By default, the output is written to standard output\&.
+.RE
+.SH "SEE ALSO"
+.PP
+
+\fBbind10\fR(8),
+BIND 10 Guide\&.
+.SH "HISTORY"
+.PP
+The
+\fBb10\-showtech\fR
+daemon was initially implemented by ISC staff in June, 2012\&.
+.SH "COPYRIGHT"
+.br
+Copyright \(co 2012 Internet Systems Consortium, Inc. ("ISC")
+.br
diff --git a/src/bin/showtech/b10-showtech.xml b/src/bin/showtech/b10-showtech.xml
new file mode 100644
index 0000000..fe11ed1
--- /dev/null
+++ b/src/bin/showtech/b10-showtech.xml
@@ -0,0 +1,106 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+               "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+	       [<!ENTITY mdash "—">]>
+<!--
+ - Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+ -
+ - Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS.  IN NO EVENT SHALL ISC 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.
+-->
+
+<refentry>
+
+  <refentryinfo>
+    <date>June 26, 2012</date>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>b10-showtech</refentrytitle>
+    <manvolnum>1</manvolnum>
+    <refmiscinfo>BIND10</refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>b10-showtech</refname>
+    <refpurpose>BIND 10 system information display tool</refpurpose>
+  </refnamediv>
+
+  <docinfo>
+    <copyright>
+      <year>2012</year>
+      <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+    </copyright>
+  </docinfo>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>b10-showtech</command>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>DESCRIPTION</title>
+    <para>
+      The <command>b10-showtech</command> program collects and outputs a
+      variety of information about the system that BIND 10 is running
+      on. This information can be useful to people involved in debugging
+      and technical support.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>ARGUMENTS</title>
+
+    <variablelist>
+
+      <varlistentry>
+        <term>-h</term>
+        <listitem><para>
+          Displays usage instructions.
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-o <replaceable class="parameter">output-file</replaceable></term>
+        <listitem><para>
+          If an output file is specified, the output
+          of <command>b10-showtech</command> is written to this file. By
+          default, the output is written to standard output.
+        </para></listitem>
+      </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  <refsect1>
+    <title>SEE ALSO</title>
+    <para>
+      <citerefentry>
+        <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citetitle>BIND 10 Guide</citetitle>.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>HISTORY</title>
+    <para>
+      The <command>b10-showtech</command> daemon was initially
+      implemented by ISC staff in June, 2012.
+    </para>
+  </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/src/bin/showtech/showtech.py.in b/src/bin/showtech/showtech.py.in
new file mode 100755
index 0000000..5b67847
--- /dev/null
+++ b/src/bin/showtech/showtech.py.in
@@ -0,0 +1,127 @@
+#!@PYTHON@
+
+# Copyright (C) 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
+# 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 showtech program.
+
+"""
+
+import sys; sys.path.append ('@@PYTHONPATH@@')
+import getopt
+import isc.util.process
+from isc.sysinfo import *
+
+isc.util.process.rename()
+
+def usage():
+    print("Usage: %s [-h] [-o <output-file>]" % sys.argv[0], \
+              file=sys.stderr)
+    exit(1)
+
+def main():
+    try:
+        opts, args = getopt.getopt(sys.argv[1:], "o:h", \
+                                       ["output", "help"])
+    except getopt.GetoptError as e:
+        print(str(e))
+        usage()
+        exit(1)
+
+    output_filename = None
+    for option, arg in opts:
+        if option in ("-o", "--output"):
+            output_filename = arg
+        elif option in ("-h", "--help"):
+            usage()
+        else:
+            assert False, "unhandled option"
+
+    if output_filename is None:
+        f = sys.stdout
+    else:
+        f = open(output_filename, 'w')
+
+    s = SysInfoFromFactory()
+
+    f.write('BIND 10 ShowTech tool\n')
+    f.write('=====================\n')
+
+    f.write('\nCPU\n');
+    f.write(' + Number of processors: %d\n' % (s.get_num_processors()))
+    f.write(' + Endianness: %s\n' % (s.get_endianness()))
+
+    f.write('\nPlatform\n');
+    f.write(' + Operating system: %s\n' % (s.get_platform_name()))
+    f.write(' + Distribution: %s\n' % (s.get_platform_distro()))
+    f.write(' + Kernel version: %s\n' % (s.get_platform_version()))
+
+    f.write(' + SMP kernel: ')
+    if s.get_platform_is_smp():
+        f.write('yes')
+    else:
+        f.write('no')
+    f.write('\n')
+
+    f.write(' + Machine name: %s\n' % (s.get_platform_machine()))
+    f.write(' + Hostname: %s\n' % (s.get_platform_hostname()))
+    f.write(' + Uptime: %d seconds\n' % (s.get_uptime()))
+
+    l = s.get_loadavg()
+    f.write(' + Loadavg: %f %f %f\n' % (l[0], l[1], l[2]))
+
+    f.write('\nMemory\n');
+    f.write(' + Total: %d bytes\n' % (s.get_mem_total()))
+    f.write(' + Free: %d bytes\n' % (s.get_mem_free()))
+    f.write(' + Cached: %d bytes\n' % (s.get_mem_cached()))
+    f.write(' + Buffers: %d bytes\n' % (s.get_mem_buffers()))
+    f.write(' + Swap total: %d bytes\n' % (s.get_mem_swap_total()))
+    f.write(' + Swap free: %d bytes\n' % (s.get_mem_swap_free()))
+
+    f.write('\n\nNetwork\n');
+    f.write('-------\n\n');
+
+    f.write('Interfaces\n')
+    f.write('~~~~~~~~~~\n\n')
+
+    f.write(s.get_net_interfaces())
+
+    f.write('\nRouting table\n')
+    f.write('~~~~~~~~~~~~~\n\n')
+    f.write(s.get_net_routing_table())
+
+    f.write('\nStatistics\n')
+    f.write('~~~~~~~~~~\n\n')
+    f.write(s.get_net_stats())
+
+    f.write('\nConnections\n')
+    f.write('~~~~~~~~~~~\n\n')
+    f.write(s.get_net_connections())
+
+    try:
+        if os.getuid() != 0:
+            sys.stderr.write('\n')
+            sys.stderr.write('NOTE: You have to run this program as the root user so that it can\n')
+            sys.stderr.write('      collect all the information it requires. Some information is\n')
+            sys.stderr.write('      only available to the root user.\n\n')
+    except Exception:
+        pass
+
+    if f != sys.stdout:
+        f.close()
+
+if __name__ == '__main__':
+    main()
diff --git a/src/lib/config/tests/ccsession_unittests.cc b/src/lib/config/tests/ccsession_unittests.cc
index 3fca741..e07c5a3 100644
--- a/src/lib/config/tests/ccsession_unittests.cc
+++ b/src/lib/config/tests/ccsession_unittests.cc
@@ -33,7 +33,6 @@ using namespace isc::data;
 using namespace isc::config;
 using namespace isc::cc;
 using namespace std;
-using namespace boost;
 
 namespace {
 std::string
@@ -52,6 +51,7 @@ protected:
                       root_name(isc::log::getRootLoggerName())
     {
         // upon creation of a ModuleCCSession, the class
+
         // sends its specification to the config manager.
         // it expects an ok answer back, so everytime we
         // create a ModuleCCSession, we must set an initial
@@ -740,8 +740,9 @@ protected:
         registerCommand(const string& recipient)
     {
         return (mccs_.groupRecvMsgAsync(
-            bind(&AsyncReceiveCCSessionTest::callback, this, next_flag_ ++, _1,
-                 _2, _3), false, -1, recipient));
+                    boost::bind(&AsyncReceiveCCSessionTest::callback, this,
+                                next_flag_++, _1, _2, _3), false, -1,
+                    recipient));
     }
     /// \brief Convenience function to queue a request to get a reply
     ///     message.
@@ -749,8 +750,8 @@ protected:
         registerReply(int seq)
     {
         return (mccs_.groupRecvMsgAsync(
-            bind(&AsyncReceiveCCSessionTest::callback, this, next_flag_ ++, _1,
-                 _2, _3), true, seq));
+                    boost::bind(&AsyncReceiveCCSessionTest::callback, this,
+                                next_flag_++, _1, _2, _3), true, seq));
     }
     /// \brief Check the next called callback was with this flag
     void called(int flag) {
diff --git a/src/lib/datasrc/rbtree.h b/src/lib/datasrc/rbtree.h
index 39646ac..106aaa8 100644
--- a/src/lib/datasrc/rbtree.h
+++ b/src/lib/datasrc/rbtree.h
@@ -1260,6 +1260,9 @@ RBTree<T>::previousNode(RBTreeNodeChain<T>& node_path) const {
             // already, which located the exact node. The rest of the function
             // goes one domain left and returns it for us.
             break;
+        default:
+            // This must not happen as Name::compare() never returns NONE.
+            isc_throw(isc::Unexpected, "Name::compare() returned unexpected result");
     }
 
     // So, the node_path now contains the path to a node we want previous for.
diff --git a/src/lib/dns/labelsequence.cc b/src/lib/dns/labelsequence.cc
index 4c95632..c95c5b0 100644
--- a/src/lib/dns/labelsequence.cc
+++ b/src/lib/dns/labelsequence.cc
@@ -71,6 +71,21 @@ LabelSequence::equals(const LabelSequence& other, bool case_sensitive) const {
     return (true);
 }
 
+NameComparisonResult
+LabelSequence::compare(const LabelSequence& other,
+                       bool case_sensitive) const {
+    if (isAbsolute() ^ other.isAbsolute()) {
+        return (NameComparisonResult(0, 0, NameComparisonResult::NONE));
+    }
+
+    return (name_.compare(other.name_,
+                          first_label_,
+                          other.first_label_,
+                          last_label_,
+                          other.last_label_,
+                          case_sensitive));
+}
+
 void
 LabelSequence::stripLeft(size_t i) {
     if (i >= getLabelCount()) {
diff --git a/src/lib/dns/labelsequence.h b/src/lib/dns/labelsequence.h
index d2d9d08..25adc71 100644
--- a/src/lib/dns/labelsequence.h
+++ b/src/lib/dns/labelsequence.h
@@ -88,10 +88,10 @@ public:
     /// \return The length of the data of the label sequence in octets.
     size_t getDataLength() const;
 
-    /// \brief Compares two label sequences.
+    /// \brief Compares two label sequences for equality.
     ///
     /// Performs a (optionally case-insensitive) comparison between this
-    /// LabelSequence and another LabelSequence.
+    /// LabelSequence and another LabelSequence for equality.
     ///
     /// \param other The LabelSequence to compare with
     /// \param case_sensitive If true, comparison is case-insensitive
@@ -99,6 +99,18 @@ public:
     ///         and contain the same data.
     bool equals(const LabelSequence& other, bool case_sensitive = false) const;
 
+    /// \brief Compares two label sequences.
+    ///
+    /// Performs a (optionally case-insensitive) comparison between this
+    /// LabelSequence and another LabelSequence.
+    ///
+    /// \param other The LabelSequence to compare with
+    /// \param case_sensitive If true, comparison is case-insensitive
+    /// \return a <code>NameComparisonResult</code> object representing the
+    /// comparison result.
+    NameComparisonResult compare(const LabelSequence& other,
+                                 bool case_sensitive = false) const;
+
     /// \brief Remove labels from the front of this LabelSequence
     ///
     /// \note No actual memory is changed, this operation merely updates the
diff --git a/src/lib/dns/name.cc b/src/lib/dns/name.cc
index 37c35f1..d7df7bd 100644
--- a/src/lib/dns/name.cc
+++ b/src/lib/dns/name.cc
@@ -435,13 +435,33 @@ Name::toText(bool omit_final_dot) const {
 
 NameComparisonResult
 Name::compare(const Name& other) const {
+    return (compare(other, 0, 0, labelcount_, other.labelcount_));
+}
+
+NameComparisonResult
+Name::compare(const Name& other,
+              unsigned int first_label,
+              unsigned int first_label_other,
+              unsigned int last_label,
+              unsigned int last_label_other,
+              bool case_sensitive) const {
     // Determine the relative ordering under the DNSSEC order relation of
     // 'this' and 'other', and also determine the hierarchical relationship
     // of the names.
 
+    if ((first_label > last_label) ||
+        (first_label_other > last_label_other)) {
+        isc_throw(BadValue, "Bad label index ranges were passed");
+    }
+
+    if ((first_label > labelcount_) ||
+        (first_label_other > other.labelcount_)) {
+        isc_throw(BadValue, "Bad first label indices were passed");
+    }
+
     unsigned int nlabels = 0;
-    unsigned int l1 = labelcount_;
-    unsigned int l2 = other.labelcount_;
+    int l1 = last_label - first_label;
+    int l2 = last_label_other - first_label_other;
     int ldiff = (int)l1 - (int)l2;
     unsigned int l = (ldiff < 0) ? l1 : l2;
 
@@ -449,8 +469,8 @@ Name::compare(const Name& other) const {
         --l;
         --l1;
         --l2;
-        size_t pos1 = offsets_[l1];
-        size_t pos2 = other.offsets_[l2];
+        size_t pos1 = offsets_[l1 + first_label];
+        size_t pos2 = other.offsets_[l2 + first_label_other];
         unsigned int count1 = ndata_[pos1++];
         unsigned int count2 = other.ndata_[pos2++];
 
@@ -464,19 +484,39 @@ Name::compare(const Name& other) const {
         while (count > 0) {
             uint8_t label1 = ndata_[pos1];
             uint8_t label2 = other.ndata_[pos2];
+            int chdiff;
+
+            if (case_sensitive) {
+                chdiff = (int)label1 - (int)label2;
+            } else {
+                chdiff = (int)maptolower[label1] - (int)maptolower[label2];
+            }
 
-            int chdiff = (int)maptolower[label1] - (int)maptolower[label2];
             if (chdiff != 0) {
-                return (NameComparisonResult(chdiff, nlabels,
-                                         NameComparisonResult::COMMONANCESTOR));
+                if ((nlabels == 0) &&
+                    ((last_label < labelcount_) ||
+                     (last_label_other < other.labelcount_))) {
+                    return (NameComparisonResult(0, 0,
+                                                 NameComparisonResult::NONE));
+                } else {
+                    return (NameComparisonResult(chdiff, nlabels,
+                                                 NameComparisonResult::COMMONANCESTOR));
+                }
             }
             --count;
             ++pos1;
             ++pos2;
         }
         if (cdiff != 0) {
+            if ((nlabels == 0) &&
+                ((last_label < labelcount_) ||
+                 (last_label_other < other.labelcount_))) {
+                return (NameComparisonResult(0, 0,
+                                             NameComparisonResult::NONE));
+            } else {
                 return (NameComparisonResult(cdiff, nlabels,
-                                         NameComparisonResult::COMMONANCESTOR));
+                                             NameComparisonResult::COMMONANCESTOR));
+            }
         }
         ++nlabels;
     }
diff --git a/src/lib/dns/name.h b/src/lib/dns/name.h
index 41024fc..6cfa546 100644
--- a/src/lib/dns/name.h
+++ b/src/lib/dns/name.h
@@ -142,7 +142,8 @@ public:
         SUPERDOMAIN = 0,
         SUBDOMAIN = 1,
         EQUAL = 2,
-        COMMONANCESTOR = 3
+        COMMONANCESTOR = 3,
+        NONE = 4
     };
 
     ///
@@ -404,6 +405,36 @@ public:
     /// comparison result.
     NameComparisonResult compare(const Name& other) const;
 
+private:
+    /// \brief Partially compare two <code>Name</code>s.
+    ///
+    /// This method performs a partial comparison of the
+    /// <code>Name</code> and <code>other</code> and returns the result
+    /// in the form of a <code>NameComparisonResult</code> object.
+    ///
+    /// This method can throw the BadValue exception if bad label
+    /// indices are passed.
+    ///
+    /// \param other the right-hand operand to compare against.
+    /// \param first_label the left-most label of <code>Name</code> to
+    /// begin comparing from.
+    /// \param first_label_other the left-most label of
+    /// <code>other</code> to begin comparing from.
+    /// \param last_label the right-most label of <code>Name</code> to
+    /// end comparing at.
+    /// \param last_label_other the right-most label of
+    /// <code>other</code> to end comparing at.
+    /// \param case_sensitive If true, comparison is case-insensitive
+    /// \return a <code>NameComparisonResult</code> object representing the
+    /// comparison result.
+    NameComparisonResult compare(const Name& other,
+                                 unsigned int first_label,
+                                 unsigned int first_label_other,
+                                 unsigned int last_label,
+                                 unsigned int last_label_other,
+                                 bool case_sensitive = false) const;
+
+public:
     /// \brief Return true iff two names are equal.
     ///
     /// Semantically this could be implemented based on the result of the
diff --git a/src/lib/dns/tests/labelsequence_unittest.cc b/src/lib/dns/tests/labelsequence_unittest.cc
index cd4403e..3ba1d73 100644
--- a/src/lib/dns/tests/labelsequence_unittest.cc
+++ b/src/lib/dns/tests/labelsequence_unittest.cc
@@ -142,6 +142,223 @@ TEST_F(LabelSequenceTest, equals_insensitive) {
     EXPECT_TRUE(ls11.equals(ls12));
 }
 
+// Compare tests
+TEST_F(LabelSequenceTest, compare) {
+    // "example.org." and "example.org.", case sensitive
+    NameComparisonResult result = ls1.compare(ls3, true);
+    EXPECT_EQ(isc::dns::NameComparisonResult::EQUAL,
+              result.getRelation());
+    EXPECT_EQ(0, result.getOrder());
+    EXPECT_EQ(3, result.getCommonLabels());
+
+    // "example.org." and "example.ORG.", case sensitive
+    result = ls3.compare(ls5, true);
+    EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
+              result.getRelation());
+    EXPECT_LT(0, result.getOrder());
+    EXPECT_EQ(1, result.getCommonLabels());
+
+    // "example.org." and "example.ORG.", case in-sensitive
+    result = ls3.compare(ls5);
+    EXPECT_EQ(isc::dns::NameComparisonResult::EQUAL,
+              result.getRelation());
+    EXPECT_EQ(0, result.getOrder());
+    EXPECT_EQ(3, result.getCommonLabels());
+
+    Name na("a.example.org");
+    Name nb("b.example.org");
+    LabelSequence lsa(na);
+    LabelSequence lsb(nb);
+
+    // "a.example.org." and "b.example.org.", case in-sensitive
+    result = lsa.compare(lsb);
+    EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
+              result.getRelation());
+    EXPECT_GT(0, result.getOrder());
+    EXPECT_EQ(3, result.getCommonLabels());
+
+    // "example.org." and "b.example.org.", case in-sensitive
+    lsa.stripLeft(1);
+    result = lsa.compare(lsb);
+    EXPECT_EQ(isc::dns::NameComparisonResult::SUPERDOMAIN,
+              result.getRelation());
+    EXPECT_GT(0, result.getOrder());
+    EXPECT_EQ(3, result.getCommonLabels());
+
+    Name nc("g.f.e.d.c.example.org");
+    LabelSequence lsc(nc);
+
+    // "g.f.e.d.c.example.org." and "b.example.org" (not absolute), case
+    // in-sensitive
+    lsb.stripRight(1);
+    result = lsc.compare(lsb);
+    EXPECT_EQ(isc::dns::NameComparisonResult::NONE,
+              result.getRelation());
+    EXPECT_EQ(0, result.getOrder());
+    EXPECT_EQ(0, result.getCommonLabels());
+
+    // "g.f.e.d.c.example.org." and "example.org.", case in-sensitive
+    result = lsc.compare(ls1);
+    EXPECT_EQ(isc::dns::NameComparisonResult::SUBDOMAIN,
+              result.getRelation());
+    EXPECT_LT(0, result.getOrder());
+    EXPECT_EQ(3, result.getCommonLabels());
+
+    // "e.d.c.example.org." and "example.org.", case in-sensitive
+    lsc.stripLeft(2);
+    result = lsc.compare(ls1);
+    EXPECT_EQ(isc::dns::NameComparisonResult::SUBDOMAIN,
+              result.getRelation());
+    EXPECT_LT(0, result.getOrder());
+    EXPECT_EQ(3, result.getCommonLabels());
+
+    // "example.org." and "example.org.", case in-sensitive
+    lsc.stripLeft(3);
+    result = lsc.compare(ls1);
+    EXPECT_EQ(isc::dns::NameComparisonResult::EQUAL,
+              result.getRelation());
+    EXPECT_EQ(0, result.getOrder());
+    EXPECT_EQ(3, result.getCommonLabels());
+
+    // "." and "example.org.", case in-sensitive
+    lsc.stripLeft(2);
+    result = lsc.compare(ls1);
+    EXPECT_EQ(isc::dns::NameComparisonResult::SUPERDOMAIN,
+              result.getRelation());
+    EXPECT_GT(0, result.getOrder());
+    EXPECT_EQ(1, result.getCommonLabels());
+
+    Name nd("a.b.c.isc.example.org");
+    LabelSequence lsd(nd);
+    Name ne("w.x.y.isc.EXAMPLE.org");
+    LabelSequence lse(ne);
+
+    // "a.b.c.isc.example.org." and "w.x.y.isc.EXAMPLE.org.",
+    // case sensitive
+    result = lsd.compare(lse, true);
+    EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
+              result.getRelation());
+    EXPECT_LT(0, result.getOrder());
+    EXPECT_EQ(2, result.getCommonLabels());
+
+    // "a.b.c.isc.example.org." and "w.x.y.isc.EXAMPLE.org.",
+    // case in-sensitive
+    result = lsd.compare(lse);
+    EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
+              result.getRelation());
+    EXPECT_GT(0, result.getOrder());
+    EXPECT_EQ(4, result.getCommonLabels());
+
+    // "isc.example.org." and "isc.EXAMPLE.org.", case sensitive
+    lsd.stripLeft(3);
+    lse.stripLeft(3);
+    result = lsd.compare(lse, true);
+    EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
+              result.getRelation());
+    EXPECT_LT(0, result.getOrder());
+    EXPECT_EQ(2, result.getCommonLabels());
+
+    // "isc.example.org." and "isc.EXAMPLE.org.", case in-sensitive
+    result = lsd.compare(lse);
+    EXPECT_EQ(isc::dns::NameComparisonResult::EQUAL,
+              result.getRelation());
+    EXPECT_EQ(0, result.getOrder());
+    EXPECT_EQ(4, result.getCommonLabels());
+
+    Name nf("a.b.c.isc.example.org");
+    LabelSequence lsf(nf);
+    Name ng("w.x.y.isc.EXAMPLE.org");
+    LabelSequence lsg(ng);
+
+    // "a.b.c.isc.example.org." and "w.x.y.isc.EXAMPLE.org" (not
+    // absolute), case in-sensitive
+    lsg.stripRight(1);
+    result = lsg.compare(lsf);
+    EXPECT_EQ(isc::dns::NameComparisonResult::NONE,
+              result.getRelation());
+    EXPECT_EQ(0, result.getOrder());
+    EXPECT_EQ(0, result.getCommonLabels());
+
+    // "a.b.c.isc.example.org" (not absolute) and
+    // "w.x.y.isc.EXAMPLE.org" (not absolute), case in-sensitive
+    lsf.stripRight(1);
+    result = lsg.compare(lsf);
+    EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
+              result.getRelation());
+    EXPECT_LT(0, result.getOrder());
+    EXPECT_EQ(3, result.getCommonLabels());
+
+    // "a.b.c.isc.example" (not absolute) and
+    // "w.x.y.isc.EXAMPLE" (not absolute), case in-sensitive
+    lsf.stripRight(1);
+    lsg.stripRight(1);
+    result = lsg.compare(lsf);
+    EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
+              result.getRelation());
+    EXPECT_LT(0, result.getOrder());
+    EXPECT_EQ(2, result.getCommonLabels());
+
+    // "a.b.c" (not absolute) and
+    // "w.x.y" (not absolute), case in-sensitive
+    lsf.stripRight(2);
+    lsg.stripRight(2);
+    result = lsg.compare(lsf);
+    EXPECT_EQ(isc::dns::NameComparisonResult::NONE,
+              result.getRelation());
+    EXPECT_EQ(0, result.getOrder());
+    EXPECT_EQ(0, result.getCommonLabels());
+
+    Name nh("aexample.org");
+    LabelSequence lsh(nh);
+    Name ni("bexample.org");
+    LabelSequence lsi(ni);
+
+    // "aexample.org" (not absolute) and
+    // "bexample.org" (not absolute), case in-sensitive
+    lsh.stripRight(1);
+    lsi.stripRight(1);
+    result = lsh.compare(lsi);
+    EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
+              result.getRelation());
+    EXPECT_GT(0, result.getOrder());
+    EXPECT_EQ(1, result.getCommonLabels());
+
+    // "aexample" (not absolute) and
+    // "bexample" (not absolute), case in-sensitive
+    lsh.stripRight(1);
+    lsi.stripRight(1);
+    result = lsh.compare(lsi);
+    EXPECT_EQ(isc::dns::NameComparisonResult::NONE,
+              result.getRelation());
+    EXPECT_EQ(0, result.getOrder());
+    EXPECT_EQ(0, result.getCommonLabels());
+
+    Name nj("example.org");
+    LabelSequence lsj(nj);
+    Name nk("example.org");
+    LabelSequence lsk(nk);
+
+    // "example.org" (not absolute) and
+    // "example.org" (not absolute), case in-sensitive
+    lsj.stripRight(1);
+    lsk.stripRight(1);
+    result = lsj.compare(lsk);
+    EXPECT_EQ(isc::dns::NameComparisonResult::EQUAL,
+              result.getRelation());
+    EXPECT_EQ(0, result.getOrder());
+    EXPECT_EQ(2, result.getCommonLabels());
+
+    // "example" (not absolute) and
+    // "example" (not absolute), case in-sensitive
+    lsj.stripRight(1);
+    lsk.stripRight(1);
+    result = lsj.compare(lsk);
+    EXPECT_EQ(isc::dns::NameComparisonResult::EQUAL,
+              result.getRelation());
+    EXPECT_EQ(0, result.getOrder());
+    EXPECT_EQ(1, result.getCommonLabels());
+}
+
 void
 getDataCheck(const uint8_t* expected_data, size_t expected_len,
              const LabelSequence& ls)
diff --git a/src/lib/python/isc/Makefile.am b/src/lib/python/isc/Makefile.am
index 80fd222..e072de8 100644
--- a/src/lib/python/isc/Makefile.am
+++ b/src/lib/python/isc/Makefile.am
@@ -1,5 +1,5 @@
 SUBDIRS = datasrc cc config dns log net notify util testutils acl bind10
-SUBDIRS += xfrin log_messages server_common ddns
+SUBDIRS += xfrin log_messages server_common ddns sysinfo
 
 python_PYTHON = __init__.py
 
diff --git a/src/lib/python/isc/sysinfo/Makefile.am b/src/lib/python/isc/sysinfo/Makefile.am
new file mode 100644
index 0000000..aebbc2e
--- /dev/null
+++ b/src/lib/python/isc/sysinfo/Makefile.am
@@ -0,0 +1,11 @@
+SUBDIRS = . tests
+
+python_PYTHON = __init__.py
+python_PYTHON += sysinfo.py
+
+pythondir = $(pyexecdir)/isc/sysinfo
+
+CLEANDIRS = __pycache__
+
+clean-local:
+	rm -rf $(CLEANDIRS)
diff --git a/src/lib/python/isc/sysinfo/__init__.py b/src/lib/python/isc/sysinfo/__init__.py
new file mode 100644
index 0000000..c632b30
--- /dev/null
+++ b/src/lib/python/isc/sysinfo/__init__.py
@@ -0,0 +1 @@
+from isc.sysinfo.sysinfo import *
diff --git a/src/lib/python/isc/sysinfo/sysinfo.py b/src/lib/python/isc/sysinfo/sysinfo.py
new file mode 100644
index 0000000..efba0f6
--- /dev/null
+++ b/src/lib/python/isc/sysinfo/sysinfo.py
@@ -0,0 +1,286 @@
+# Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+#
+# 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.
+
+'''This module returns system information.'''
+
+import os
+import sys
+import re
+import subprocess
+import os.path
+import platform
+
+class SysInfo:
+    def __init__(self):
+        self._num_processors = -1
+        self._endianness = 'Unknown'
+        self._hostname = ''
+        self._platform_name = 'Unknown'
+        self._platform_version = 'Unknown'
+        self._platform_machine = 'Unknown'
+        self._platform_is_smp = False
+        self._uptime = -1
+        self._loadavg = [-1.0, -1.0, -1.0]
+        self._mem_total = -1
+        self._mem_free = -1
+        self._mem_cached = -1
+        self._mem_buffers = -1
+        self._mem_swap_total = -1
+        self._mem_swap_free = -1
+        self._platform_distro = 'Unknown'
+        self._net_interfaces = 'Unknown'
+        self._net_routing_table = 'Unknown'
+        self._net_stats = 'Unknown'
+        self._net_connections = 'Unknown'
+
+    def get_num_processors(self):
+        """Returns the number of processors. This is the number of
+        hyperthreads when hyper-threading is enabled.
+        """
+        return self._num_processors
+
+    def get_endianness(self):
+        """Returns 'big' or 'little'."""
+        return self._endianness
+
+    def get_platform_hostname(self):
+        """Returns the hostname of the system."""
+        return self._hostname
+
+    def get_platform_name(self):
+        """Returns the platform name (uname -s)."""
+        return self._platform_name
+
+    def get_platform_version(self):
+        """Returns the platform version (uname -v)."""
+        return self._platform_version
+
+    def get_platform_machine(self):
+        """Returns the platform machine architecture."""
+        return self._platform_machine
+
+    def get_platform_is_smp(self):
+        """Returns True if an SMP kernel is being used, False otherwise."""
+        return self._platform_is_smp
+
+    def get_platform_distro(self):
+        """Returns the name of the OS distribution in use."""
+        return self._platform_distro
+
+    def get_uptime(self):
+        """Returns the uptime in seconds."""
+        return self._uptime
+
+    def get_loadavg(self):
+        """Returns the load average as 3 floating point values in an array."""
+        return self._loadavg
+
+    def get_mem_total(self):
+        """Returns the total amount of memory in bytes."""
+        return self._mem_total
+
+    def get_mem_free(self):
+        """Returns the amount of free memory in bytes."""
+        return self._mem_free
+
+    def get_mem_cached(self):
+        """Returns the amount of cached memory in bytes."""
+        return self._mem_cached
+
+    def get_mem_buffers(self):
+        """Returns the amount of buffer in bytes."""
+        return self._mem_buffers
+
+    def get_mem_swap_total(self):
+        """Returns the total amount of swap in bytes."""
+        return self._mem_swap_total
+
+    def get_mem_swap_free(self):
+        """Returns the amount of free swap in bytes."""
+        return self._mem_swap_free
+
+    def get_net_interfaces(self):
+        """Returns information about network interfaces (as a multi-line string)."""
+        return self._net_interfaces
+
+    def get_net_routing_table(self):
+        """Returns information about network routing table (as a multi-line string)."""
+        return self._net_routing_table
+
+    def get_net_stats(self):
+        """Returns network statistics (as a multi-line string)."""
+        return self._net_stats
+
+    def get_net_connections(self):
+        """Returns network connection information (as a multi-line string)."""
+        return self._net_connections
+
+class SysInfoLinux(SysInfo):
+    """Linux implementation of the SysInfo class.
+    See the base class documentation for more information.
+    """
+    def __init__(self):
+        super().__init__()
+
+        self._num_processors = os.sysconf('SC_NPROCESSORS_CONF')
+        self._endianness = sys.byteorder
+
+        with open('/proc/sys/kernel/hostname') as f:
+            self._hostname = f.read().strip()
+
+        u = os.uname()
+        self._platform_name = u[0]
+        self._platform_version = u[2]
+        self._platform_machine = u[4]
+
+        with open('/proc/version') as f:
+            self._platform_is_smp = ' SMP ' in f.read().strip()
+
+        with open('/proc/uptime') as f:
+            u = f.read().strip().split(' ')
+            if len(u) > 1:
+                self._uptime = int(round(float(u[0])))
+
+        with open('/proc/loadavg') as f:
+            l = f.read().strip().split(' ')
+            if len(l) >= 3:
+                self._loadavg = [float(l[0]), float(l[1]), float(l[2])]
+
+        with open('/proc/meminfo') as f:
+            m = f.readlines()
+            for line in m:
+                r = re.match('^MemTotal:\s+(.*)\s*kB', line)
+                if r:
+                    self._mem_total = int(r.group(1).strip()) * 1024
+                    continue
+                r = re.match('^MemFree:\s+(.*)\s*kB', line)
+                if r:
+                    self._mem_free = int(r.group(1).strip()) * 1024
+                    continue
+                r = re.match('^Cached:\s+(.*)\s*kB', line)
+                if r:
+                    self._mem_cached = int(r.group(1).strip()) * 1024
+                    continue
+                r = re.match('^Buffers:\s+(.*)\s*kB', line)
+                if r:
+                    self._mem_buffers = int(r.group(1).strip()) * 1024
+                    continue
+                r = re.match('^SwapTotal:\s+(.*)\s*kB', line)
+                if r:
+                    self._mem_swap_total = int(r.group(1).strip()) * 1024
+                    continue
+                r = re.match('^SwapFree:\s+(.*)\s*kB', line)
+                if r:
+                    self._mem_swap_free = int(r.group(1).strip()) * 1024
+                    continue
+
+        self._platform_distro = None
+
+        try:
+            s = subprocess.check_output(['lsb_release', '-a'])
+            for line in s.decode('utf-8').split('\n'):
+                r = re.match('^Description:(.*)', line)
+                if r:
+                    self._platform_distro = r.group(1).strip()
+                    break
+        except (subprocess.CalledProcessError, OSError):
+            pass
+
+        if self._platform_distro is None:
+            files = ['/etc/debian_release',
+                     '/etc/debian_version',
+                     '/etc/SuSE-release',
+                     '/etc/UnitedLinux-release',
+                     '/etc/mandrake-release',
+                     '/etc/gentoo-release',
+                     '/etc/fedora-release',
+                     '/etc/redhat-release',
+                     '/etc/redhat_version',
+                     '/etc/slackware-release',
+                     '/etc/slackware-version',
+                     '/etc/arch-release',
+                     '/etc/lsb-release',
+                     '/etc/mageia-release']
+            for fn in files:
+                if os.path.exists(fn):
+                    with open(fn) as f:
+                        self._platform_distro = f.read().strip()
+                    break
+
+        if self._platform_distro is None:
+            self._platform_distro = 'Unknown'
+
+        self._net_interfaces = None
+
+        try:
+            s = subprocess.check_output(['ip', 'addr'])
+            self._net_interfaces = s.decode('utf-8')
+        except (subprocess.CalledProcessError, OSError):
+            pass
+
+        if self._net_interfaces is None:
+            self._net_interfaces = 'Unknown'
+
+        self._net_routing_table = None
+
+        try:
+            s = subprocess.check_output(['ip', 'route'])
+            self._net_routing_table = s.decode('utf-8')
+            self._net_routing_table += '\n'
+            s = subprocess.check_output(['ip', '-f', 'inet6', 'route'])
+            self._net_routing_table += s.decode('utf-8')
+        except (subprocess.CalledProcessError, OSError):
+            pass
+
+        if self._net_routing_table is None:
+            self._net_routing_table = 'Unknown'
+
+        self._net_stats = None
+
+        try:
+            s = subprocess.check_output(['netstat', '-s'])
+            self._net_stats = s.decode('utf-8')
+        except (subprocess.CalledProcessError, OSError):
+            pass
+
+        if self._net_stats is None:
+            self._net_stats = 'Unknown'
+
+        self._net_connections = None
+
+        try:
+            s = subprocess.check_output(['netstat', '-apn'])
+            self._net_connections = s.decode('utf-8')
+        except (subprocess.CalledProcessError, OSError):
+            pass
+
+        if self._net_connections is None:
+            self._net_connections = 'Unknown'
+
+class SysInfoTestcase(SysInfo):
+    def __init__(self):
+        super().__init__()
+        self._endianness = 'bigrastafarian'
+        self._platform_name = 'b10test'
+        self._uptime = 131072
+
+def SysInfoFromFactory():
+    osname = platform.system()
+    if osname == 'Linux':
+        return SysInfoLinux()
+    elif osname == 'BIND10Testcase':
+        return SysInfoTestcase()
+    else:
+        return SysInfo()
diff --git a/src/lib/python/isc/sysinfo/tests/Makefile.am b/src/lib/python/isc/sysinfo/tests/Makefile.am
new file mode 100644
index 0000000..9759c77
--- /dev/null
+++ b/src/lib/python/isc/sysinfo/tests/Makefile.am
@@ -0,0 +1,23 @@
+PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
+PYTESTS = sysinfo_test.py
+EXTRA_DIST = $(PYTESTS)
+
+# If necessary (rare cases), explicitly specify paths to dynamic libraries
+# required by loadable python modules.
+if SET_ENV_LIBRARY_PATH
+LIBRARY_PATH_PLACEHOLDER = $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/cryptolink/.libs:$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/lib/cc/.libs:$(abs_top_builddir)/src/lib/config/.libs:$(abs_top_builddir)/src/lib/log/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/acl/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/datasrc/.libs:$$$(ENV_LIBRARY_PATH)
+endif
+
+# test using command-line arguments, so use check-local target instead of TESTS
+check-local:
+if ENABLE_PYTHON_COVERAGE
+	touch $(abs_top_srcdir)/.coverage
+	rm -f .coverage
+	${LN_S} $(abs_top_srcdir)/.coverage .coverage
+endif
+	for pytest in $(PYTESTS) ; do \
+	echo Running test: $$pytest ; \
+	$(LIBRARY_PATH_PLACEHOLDER) \
+	PYTHONPATH=$(COMMON_PYTHON_PATH) \
+	$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
+	done
diff --git a/src/lib/python/isc/sysinfo/tests/sysinfo_test.py b/src/lib/python/isc/sysinfo/tests/sysinfo_test.py
new file mode 100644
index 0000000..93985c7
--- /dev/null
+++ b/src/lib/python/isc/sysinfo/tests/sysinfo_test.py
@@ -0,0 +1,197 @@
+# Copyright (C) 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
+# 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.
+
+from isc.sysinfo import *
+import os
+import unittest
+import platform
+import subprocess
+
+def _my_testcase_platform_system():
+    return 'BIND10Testcase'
+
+def _my_linux_platform_system():
+    return 'Linux'
+
+def _my_linux_os_sysconf(key):
+    if key == 'SC_NPROCESSORS_CONF':
+        return 42
+    assert False, 'Unhandled key'
+
+class MyFile:
+    def __init__(self, filename):
+        self._filename = filename
+
+    def read(self):
+        if self._filename == '/proc/sys/kernel/hostname':
+            return 'myhostname'
+        elif self._filename == '/proc/version':
+            return 'An SMP version string'
+        elif self._filename == '/proc/uptime':
+            return '86400.75 139993.71'
+        elif self._filename == '/proc/loadavg':
+            return '0.1 0.2 0.3 0.4'
+        else:
+            assert False, 'Unhandled filename'
+
+    def readlines(self):
+        if self._filename == '/proc/meminfo':
+            return ['MemTotal:        3083872 kB',
+                    'MemFree:          870492 kB',
+                    'Buffers:           27412 kB',
+                    'Cached:          1303860 kB',
+                    'SwapTotal:       4194300 kB',
+                    'SwapFree:        3999464 kB']
+        else:
+            assert False, 'Unhandled filename'
+
+    def close(self):
+        return
+
+    def __enter__(self):
+        return self
+
+    def __exit__(self, type, value, traceback):
+        return
+
+def _my_linux_open(filename):
+    return MyFile(filename)
+
+def _my_linux_subprocess_check_output(command):
+    assert type(command) == list, 'command argument is not a list'
+    if command == ['lsb_release', '-a']:
+        return b'Description: My Distribution\n'
+    elif command == ['ip', 'addr']:
+        return b'qB2osV6vUOjqm3P/+tQ4d92xoYz8/U8P9v3KWRpNwlI=\n'
+    elif command == ['ip', 'route']:
+        return b'VGWAS92AlS14Pl2xqENJs5P2Ihe6Nv9g181Mu6Zz+aQ=\n'
+    elif command == ['ip', '-f', 'inet6', 'route']:
+        return b'XfizswwNA9NkXz6K36ZExpjV08Y5IXkHI8jjDSV+5Nc=\n'
+    elif command == ['netstat', '-s']:
+        return b'osuxbrcc1g9VgaF4yf3FrtfodrfATrbSnjhqhuQSAs8=\n'
+    elif command == ['netstat', '-apn']:
+        return b'Z+w0lwa02/T+5+EIio84rrst/Dtizoz/aL9Im7J7ESA=\n'
+    else:
+        assert False, 'Unhandled command'
+
+class SysInfoTest(unittest.TestCase):
+    def test_sysinfo(self):
+        """Test that the various methods on SysInfo exist and return data."""
+
+        s = SysInfo()
+        self.assertEqual(-1, s.get_num_processors())
+        self.assertEqual('Unknown', s.get_endianness())
+        self.assertEqual('', s.get_platform_hostname())
+        self.assertEqual('Unknown', s.get_platform_name())
+        self.assertEqual('Unknown', s.get_platform_version())
+        self.assertEqual('Unknown', s.get_platform_machine())
+        self.assertFalse(s.get_platform_is_smp())
+        self.assertEqual(-1, s.get_uptime())
+        self.assertEqual([-1.0, -1.0, -1.0], s.get_loadavg())
+        self.assertEqual(-1, s.get_mem_total())
+        self.assertEqual(-1, s.get_mem_free())
+        self.assertEqual(-1, s.get_mem_cached())
+        self.assertEqual(-1, s.get_mem_buffers())
+        self.assertEqual(-1, s.get_mem_swap_total())
+        self.assertEqual(-1, s.get_mem_swap_free())
+        self.assertEqual('Unknown', s.get_platform_distro())
+        self.assertEqual('Unknown', s.get_net_interfaces())
+        self.assertEqual('Unknown', s.get_net_routing_table())
+        self.assertEqual('Unknown', s.get_net_stats())
+        self.assertEqual('Unknown', s.get_net_connections())
+
+    def test_sysinfo_factory(self):
+        """Test that SysInfoFromFactory returns a valid system-specific
+        SysInfo implementation."""
+
+        old_platform_system = platform.system
+        platform.system = _my_testcase_platform_system
+
+        s = SysInfoFromFactory()
+        self.assertEqual(-1, s.get_num_processors())
+        self.assertEqual('bigrastafarian', s.get_endianness())
+        self.assertEqual('', s.get_platform_hostname())
+        self.assertEqual('b10test', s.get_platform_name())
+        self.assertEqual('Unknown', s.get_platform_version())
+        self.assertEqual('Unknown', s.get_platform_machine())
+        self.assertFalse(s.get_platform_is_smp())
+        self.assertEqual(131072, s.get_uptime())
+        self.assertEqual([-1.0, -1.0, -1.0], s.get_loadavg())
+        self.assertEqual(-1, s.get_mem_total())
+        self.assertEqual(-1, s.get_mem_free())
+        self.assertEqual(-1, s.get_mem_cached())
+        self.assertEqual(-1, s.get_mem_buffers())
+        self.assertEqual(-1, s.get_mem_swap_total())
+        self.assertEqual(-1, s.get_mem_swap_free())
+        self.assertEqual('Unknown', s.get_platform_distro())
+        self.assertEqual('Unknown', s.get_net_interfaces())
+        self.assertEqual('Unknown', s.get_net_routing_table())
+        self.assertEqual('Unknown', s.get_net_stats())
+        self.assertEqual('Unknown', s.get_net_connections())
+
+        platform.system = old_platform_system
+
+    def test_sysinfo_linux(self):
+        """Tests the Linux implementation of SysInfo. Note that this
+        tests deep into the implementation, and not just the
+        interfaces."""
+
+        # Don't run this test on platform other than Linux as some
+        # system calls may not even be available.
+        osname = platform.system()
+        if osname != 'Linux':
+            return
+
+        # Save and replace existing implementations of library functions
+        # with mock ones for testing.
+        old_platform_system = platform.system
+        platform.system = _my_linux_platform_system
+        old_os_sysconf = os.sysconf
+        os.sysconf = _my_linux_os_sysconf
+        old_open = __builtins__.open
+        __builtins__.open = _my_linux_open
+        old_subprocess_check_output = subprocess.check_output
+        subprocess.check_output = _my_linux_subprocess_check_output
+
+        s = SysInfoFromFactory()
+        self.assertEqual(42, s.get_num_processors())
+        self.assertEqual('myhostname', s.get_platform_hostname())
+        self.assertTrue(s.get_platform_is_smp())
+        self.assertEqual(86401, s.get_uptime())
+        self.assertEqual([0.1, 0.2, 0.3], s.get_loadavg())
+        self.assertEqual(3157884928, s.get_mem_total())
+        self.assertEqual(891383808, s.get_mem_free())
+        self.assertEqual(1335152640, s.get_mem_cached())
+        self.assertEqual(28069888, s.get_mem_buffers())
+        self.assertEqual(4294963200, s.get_mem_swap_total())
+        self.assertEqual(4095451136, s.get_mem_swap_free())
+        self.assertEqual('My Distribution', s.get_platform_distro())
+
+        # These test that the corresponding tools are being called (and
+        # no further processing is done on this data). Please see the
+        # implementation functions at the top of this file.
+        self.assertEqual('qB2osV6vUOjqm3P/+tQ4d92xoYz8/U8P9v3KWRpNwlI=\n', s.get_net_interfaces())
+        self.assertEqual('VGWAS92AlS14Pl2xqENJs5P2Ihe6Nv9g181Mu6Zz+aQ=\n\nXfizswwNA9NkXz6K36ZExpjV08Y5IXkHI8jjDSV+5Nc=\n', s.get_net_routing_table())
+        self.assertEqual('osuxbrcc1g9VgaF4yf3FrtfodrfATrbSnjhqhuQSAs8=\n', s.get_net_stats())
+        self.assertEqual('Z+w0lwa02/T+5+EIio84rrst/Dtizoz/aL9Im7J7ESA=\n', s.get_net_connections())
+
+        # Restore original implementations.
+        platform.system = old_platform_system
+        os.sysconf = old_os_sysconf
+        __builtins__.open = old_open
+        subprocess.check_output = old_subprocess_check_output
+
+if __name__ == "__main__":
+    unittest.main()



More information about the bind10-changes mailing list