BIND 10 master, updated. 4b90f2ac3b8de3f1a61d7b5f743f2721c6dd34b3 [2062] Update ChangeLog

BIND 10 source code commits bind10-changes at lists.isc.org
Tue Jul 3 13:21:44 UTC 2012


The branch, master has been updated
       via  4b90f2ac3b8de3f1a61d7b5f743f2721c6dd34b3 (commit)
       via  144e80212746f8d55e6a59edcf689fec9f32ae95 (commit)
       via  a64cb609ee3d2004212634685dc8a9cae46ea617 (commit)
       via  e26eb608b1feb0dcd764a1efa1dd89561b651e19 (commit)
       via  304e2b97b852eeaee4d6be57d54dc30a413dbbd1 (commit)
       via  c7017fc5e4fb0ec1b7b3fa84f96e91d68e0a46f2 (commit)
       via  fdc9afcf5e90f2d6cacf9da65cb8ab1d7e515fd0 (commit)
       via  83e396404b5f484f1d2462664948ee6031abe638 (commit)
       via  99d2c13f8d73b423fde8e557f8775e4c24ca6d03 (commit)
       via  7e93a92e0d3f54263bd0d72cbdcb06c30229ac1f (commit)
       via  9dfb07c8ce80f1082f1d493705d95ece544dd1ca (commit)
       via  f4e22ffd7bfb3ffbc024d801f3c6dbb7312261ec (commit)
       via  04fd11bf0539ea3ace1c103cf4488cb965aec659 (commit)
       via  5c6c47046be1da96c581693c500461dff5ba9304 (commit)
       via  b2a7049b19584687962588cd5695748541ddfc32 (commit)
       via  86b50d54a6e3eac0275314ddeb77eb8ad5fbab73 (commit)
      from  1170780af08a0de33e882da5409776fe0e7f2a11 (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 4b90f2ac3b8de3f1a61d7b5f743f2721c6dd34b3
Author: Mukund Sivaraman <muks at isc.org>
Date:   Tue Jul 3 18:23:58 2012 +0530

    [2062] Update ChangeLog

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

Summary of changes:
 ChangeLog                                          |    6 +
 configure.ac                                       |    4 +
 src/bin/Makefile.am                                |    3 +-
 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/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 ++++++++++++++++++++
 src/lib/python/isc/sysinfo/tests/Makefile.am       |   16 ++
 src/lib/python/isc/sysinfo/tests/sysinfo_test.py   |  197 ++++++++++++++
 14 files changed, 725 insertions(+), 40 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
 create mode 100644 src/lib/python/isc/sysinfo/tests/Makefile.am
 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/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/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/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..209c71f
--- /dev/null
+++ b/src/lib/python/isc/sysinfo/tests/Makefile.am
@@ -0,0 +1,16 @@
+PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
+PYTESTS = sysinfo_test.py
+EXTRA_DIST = $(PYTESTS)
+
+# 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 ; \
+	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