Parcourir la source

[master] Merge branch 'trac2954', this adds dhcp-ddns process to
the source tree.

Thomas Markwalder il y a 12 ans
Parent
commit
392c5ec5d1

+ 3 - 3
configure.ac

@@ -891,9 +891,6 @@ if test X$use_shared_memory = Xyes -a "$BOOST_MAPPED_FILE_WOULDFAIL" = "yes"; th
     AC_MSG_ERROR([Boost shared memory does not compile on this system.  If you don't need it (most normal users won't) build without it by rerunning this script with --without-shared-memory; using a different compiler or a different version of Boost may also help.])
     AC_MSG_ERROR([Boost shared memory does not compile on this system.  If you don't need it (most normal users won't) build without it by rerunning this script with --without-shared-memory; using a different compiler or a different version of Boost may also help.])
 fi
 fi
 AM_CONDITIONAL([USE_SHARED_MEMORY], [test x$use_shared_memory = xyes])
 AM_CONDITIONAL([USE_SHARED_MEMORY], [test x$use_shared_memory = xyes])
-if test "x$use_shared_memory" = "xyes"; then
-    AC_DEFINE(USE_SHARED_MEMORY, 1, [Define to 1 if shared memory support is enabled])
-fi
 AC_SUBST(BOOST_MAPPED_FILE_CXXFLAG)
 AC_SUBST(BOOST_MAPPED_FILE_CXXFLAG)
 
 
 # Add some default CPP flags needed for Boost, identified by the AX macro.
 # Add some default CPP flags needed for Boost, identified by the AX macro.
@@ -1204,6 +1201,8 @@ AC_CONFIG_FILES([Makefile
                  src/bin/dhcp6/tests/Makefile
                  src/bin/dhcp6/tests/Makefile
                  src/bin/dhcp4/Makefile
                  src/bin/dhcp4/Makefile
                  src/bin/dhcp4/tests/Makefile
                  src/bin/dhcp4/tests/Makefile
+                 src/bin/d2/Makefile
+                 src/bin/d2/tests/Makefile
                  src/bin/resolver/Makefile
                  src/bin/resolver/Makefile
                  src/bin/resolver/tests/Makefile
                  src/bin/resolver/tests/Makefile
                  src/bin/resolver/bench/Makefile
                  src/bin/resolver/bench/Makefile
@@ -1384,6 +1383,7 @@ AC_OUTPUT([doc/version.ent
            src/bin/auth/gen-statisticsitems.py.pre
            src/bin/auth/gen-statisticsitems.py.pre
            src/bin/dhcp4/spec_config.h.pre
            src/bin/dhcp4/spec_config.h.pre
            src/bin/dhcp6/spec_config.h.pre
            src/bin/dhcp6/spec_config.h.pre
+           src/bin/d2/spec_config.h.pre
            src/bin/tests/process_rename_test.py
            src/bin/tests/process_rename_test.py
            src/lib/config/tests/data_def_unittests_config.h
            src/lib/config/tests/data_def_unittests_config.h
            src/lib/python/isc/config/tests/config_test
            src/lib/python/isc/config/tests/config_test

+ 1 - 0
doc/Doxyfile

@@ -689,6 +689,7 @@ INPUT                  = ../src/lib/exceptions \
                          ../src/lib/dhcp \
                          ../src/lib/dhcp \
                          ../src/lib/dhcpsrv \
                          ../src/lib/dhcpsrv \
                          ../src/bin/dhcp4 \
                          ../src/bin/dhcp4 \
+                         ../src/bin/d2 \
                          ../tests/tools/perfdhcp \
                          ../tests/tools/perfdhcp \
                          devel
                          devel
 
 

+ 1 - 1
src/bin/Makefile.am

@@ -1,5 +1,5 @@
 SUBDIRS = bind10 bindctl cfgmgr ddns loadzone msgq cmdctl auth xfrin \
 SUBDIRS = bind10 bindctl cfgmgr ddns loadzone msgq cmdctl auth xfrin \
-	xfrout usermgr zonemgr stats tests resolver sockcreator dhcp4 dhcp6 \
+	xfrout usermgr zonemgr stats tests resolver sockcreator dhcp4 dhcp6 d2\
 	dbutil sysinfo
 	dbutil sysinfo
 
 
 check-recursive: all-recursive
 check-recursive: all-recursive

+ 59 - 0
src/bin/d2/Makefile.am

@@ -0,0 +1,59 @@
+SUBDIRS = . tests
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += -I$(top_srcdir)/src/bin -I$(top_builddir)/src/bin
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+if USE_CLANGPP
+# Disable unused parameter warning caused by some Boost headers when compiling with clang
+AM_CXXFLAGS += -Wno-unused-parameter
+endif
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+
+CLEANFILES  = *.gcno *.gcda spec_config.h d2_srv_messages.h d2_srv_messages.cc
+
+man_MANS = b10-d2.8
+DISTCLEANFILES = $(man_MANS)
+EXTRA_DIST = $(man_MANS) b10-d2.xml d2.spec
+
+if GENERATE_DOCS
+b10-d2.8: b10-d2.xml
+	@XSLTPROC@ --novalid --xinclude --nonet -o $@ \
+        http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl \
+	$(srcdir)/b10-d2.xml
+
+else
+
+$(man_MANS):
+	@echo Man generation disabled.  Creating dummy $@.  Configure with --enable-generate-docs to enable it.
+	@echo Man generation disabled.  Remove this file, configure with --enable-generate-docs, and rebuild BIND 10 > $@
+
+endif
+
+spec_config.h: spec_config.h.pre
+	$(SED) -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" spec_config.h.pre >$@
+
+d2_messages.h d2_messages.cc: d2_messages.mes
+	$(top_builddir)/src/lib/log/compiler/message $(top_srcdir)/src/bin/d2/d2_messages.mes
+
+BUILT_SOURCES = spec_config.h d2_messages.h d2_messages.cc
+
+pkglibexec_PROGRAMS = b10-d2
+
+b10_d2_SOURCES  = main.cc
+b10_d2_SOURCES += d2_log.cc d2_log.h
+
+nodist_b10_d2_SOURCES = d2_messages.h d2_messages.cc
+EXTRA_DIST += d2_messages.mes
+
+b10_d2_LDADD = $(top_builddir)/src/lib/log/libb10-log.la
+b10_d2_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+
+b10_d2dir = $(pkgdatadir)
+b10_d2_DATA = d2.spec

+ 117 - 0
src/bin/d2/b10-d2.xml

@@ -0,0 +1,117 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+               "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+	       [<!ENTITY mdash "&#8212;">]>
+<!--
+ - Copyright (C) 2013  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>May 15, 2013</date>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>b10-d2</refentrytitle>
+    <manvolnum>8</manvolnum>
+    <refmiscinfo>BIND10</refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>b10-d2</refname>
+    <refpurpose>D2 process in BIND 10 architecture</refpurpose>
+  </refnamediv>
+
+  <docinfo>
+    <copyright>
+      <year>2013</year>
+      <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+    </copyright>
+  </docinfo>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>b10-d2</command>
+      <arg><option>-v</option></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>b10-d2</command>
+      <arg><option>-s</option></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+
+  <refsect1>
+    <title>DESCRIPTION</title>
+    <para>
+      The <command>b10-d2</command> daemon processes requests to
+      to update DNS mapping based on DHCP lease change events.
+    </para>
+
+  </refsect1>
+
+  <refsect1>
+    <title>ARGUMENTS</title>
+
+    <para>The arguments are as follows:</para>
+
+    <variablelist>
+
+      <varlistentry>
+        <term><option>-v</option></term>
+        <listitem><para>
+          Verbose mode sets the logging level to debug. This is primarily
+          for development purposes in stand-alone mode.
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-s</option></term>
+        <listitem><para>
+          Causes the process to run without attempting to connect to the
+          BIND10 message queue.  This is for development purposes.
+        </para></listitem>
+      </varlistentry>
+
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>SEE ALSO</title>
+    <para>
+      <citerefentry>
+        <refentrytitle>b10-d2</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>HISTORY</title>
+    <para>
+      The <command>b10-d2</command> process was first coded in
+      May 2013 by the ISC Kea/Dhcp team.
+    </para>
+  </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->

+ 21 - 0
src/bin/d2/d2.spec

@@ -0,0 +1,21 @@
+{
+  "module_spec": {
+    "module_name": "D2",
+    "module_description": "DHCP-DDNS process",
+    "config_data": [
+    ],
+    "commands": [
+        {
+            "command_name": "shutdown",
+            "command_description": "Shuts down the D2 process.",
+            "command_args": [
+                {
+                    "item_name": "pid",
+                    "item_type": "integer",
+                    "item_optional": true
+                }
+            ]
+        }
+    ]
+  }
+}

+ 26 - 0
src/bin/d2/d2_log.cc

@@ -0,0 +1,26 @@
+// Copyright (C) 2013  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.
+
+/// Defines the logger used by the top-level component of b10-d2.
+
+#include <d2/d2_log.h>
+
+namespace isc {
+namespace d2 {
+
+isc::log::Logger d2_logger("d2");
+
+} // namespace d2
+} // namespace isc
+

+ 34 - 0
src/bin/d2/d2_log.h

@@ -0,0 +1,34 @@
+// Copyright (C) 2013  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.
+
+#ifndef D2_LOG_H
+#define D2_LOG_H
+
+#include <log/logger_support.h>
+#include <log/macros.h>
+#include <d2/d2_messages.h>
+
+namespace isc {
+namespace d2 {
+
+/// Define the logger for the "d2" module part of b10-d2.  We could define
+/// a logger in each file, but we would want to define a common name to avoid
+/// spelling mistakes, so it is just one small step from there to define a
+/// module-common logger.
+extern isc::log::Logger d2_logger;
+
+} // namespace d2
+} // namespace isc
+
+#endif // D2_LOG_H

+ 28 - 0
src/bin/d2/d2_messages.mes

@@ -0,0 +1,28 @@
+# Copyright (C) 2013  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.
+
+$NAMESPACE isc::d2
+
+% D2_STARTING : process starting
+This is a debug message issued during a D2 process startup.
+
+% D2_START_INFO pid: %1, verbose: %2, standalone: %3
+This is a debug message issued during the D2 process startup.
+It lists some information about the parameters with which the
+process is running.
+
+% D2_SHUTDOWN : process is performing a normal shutting down
+This is a debug message issued when a D2 process shuts down
+normally in response to command to stop.
+

+ 97 - 0
src/bin/d2/main.cc

@@ -0,0 +1,97 @@
+// Copyright (C) 2013  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.
+
+#include <config.h>
+#include <d2/d2_log.h>
+#include <log/logger_support.h>
+#include <log/logger_manager.h>
+
+#include <iostream>
+
+using namespace isc::d2;
+using namespace std;
+
+/// This file contains entry point (main() function) for standard DHCP-DDNS 
+/// process, b10-d2, component for BIND10 framework. It parses command-line
+/// arguments and instantiates D2Controller class that is responsible for
+/// establishing connection with msgq (receiving commands and configuration)
+/// and also creating D2Server object as well.
+///
+/// For detailed explanation or relations between main(), D2Controller,
+/// D2Server and other classes, see \ref d2Session.
+
+namespace {
+
+const char* const D2_NAME = "b10-d2";
+
+void
+usage() {
+    cerr << "Usage: " << D2_NAME << " [-v] [-s]" << endl;
+    cerr << "  -s: stand-alone mode (don't connect to BIND10)" << endl;
+    cerr << "  -v: verbose output (only when in stand-alone mode" << endl;
+    exit(EXIT_FAILURE);
+}
+} // end of anonymous namespace
+
+int
+main(int argc, char* argv[]) {
+    int ch;
+
+    // @TODO NOTE these parameters are preliminary only. They are here to
+    // for symmetry with the DHCP servers.  They may or may not
+    // become part of the eventual implementation.
+
+    bool stand_alone = false;  // Should be connect to BIND10 msgq?
+    bool verbose_mode = false; // Should server be verbose?
+
+    while ((ch = getopt(argc, argv, "vsp:")) != -1) {
+        switch (ch) {
+        case 'v':
+            verbose_mode = true;
+            break;
+
+        case 's':
+            stand_alone = true;
+            break;
+
+        default:
+            usage();
+        }
+    }
+
+    // Check for extraneous parameters.
+    if (argc > optind) {
+        usage();
+    }
+
+    // Initialize logging.  If verbose, we'll use maximum verbosity.
+    // If standalone is enabled, do not buffer initial log messages
+    // Verbose logging is only enabled when in stand alone mode.
+    isc::log::initLogger(D2_NAME,
+                         ((verbose_mode && stand_alone)
+                           ? isc::log::DEBUG : isc::log::INFO),
+                         isc::log::MAX_DEBUG_LEVEL, NULL, !stand_alone);
+    LOG_INFO(d2_logger, D2_STARTING);
+    LOG_DEBUG(d2_logger, DBGLVL_START_SHUT, D2_START_INFO)
+              .arg(getpid()).arg(verbose_mode ? "yes" : "no")
+              .arg(stand_alone ? "yes" : "no" );
+
+    // For now we will sleep awhile to simulate doing something.
+    // Without at least a sleep, the process will start, exit and be
+    // restarted by Bind10/Init endlessley in a rapid succession.
+    sleep(1000);
+    LOG_INFO(d2_logger, D2_SHUTDOWN);
+    return (EXIT_SUCCESS);
+}
+

+ 15 - 0
src/bin/d2/spec_config.h.pre.in

@@ -0,0 +1,15 @@
+// Copyright (C) 2013  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.
+
+#define D2_SPECFILE_LOCATION "@prefix@/share/@PACKAGE@/d2.spec"

Fichier diff supprimé car celui-ci est trop grand
+ 65 - 0
src/bin/d2/tests/Makefile.am


+ 167 - 0
src/bin/d2/tests/d2_test.py

@@ -0,0 +1,167 @@
+# Copyright (C) 2013 Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+from init import ProcessInfo, parse_args, dump_pid, unlink_pid_file, _BASETIME
+
+import unittest
+import sys
+import os
+import signal
+import socket
+from isc.net.addr import IPAddr
+import time
+import isc
+import fcntl
+
+class TestD2Daemon(unittest.TestCase):
+    def setUp(self):
+        # Don't redirect stdout/stderr here as we want to print out things
+        # during the test
+        #
+        # However, we do want to set the logging lock directory to somewhere
+        # to which we can write - use the current working directory.  We then
+        # set the appropriate environment variable.  os.putenv() may be not
+        # supported on some platforms as suggested in
+        # http://docs.python.org/release/3.2/library/os.html?highlight=putenv#os.environ:
+        # "If the platform supports the putenv() function...". It was checked
+        # that it does not work on Ubuntu. To overcome this problem we access
+        # os.environ directly.
+        lockdir_envvar = "B10_LOCKFILE_DIR_FROM_BUILD"
+        if lockdir_envvar not in os.environ:
+            os.environ[lockdir_envvar] = os.getcwd()
+
+    def tearDown(self):
+        pass
+
+    def readPipe(self, pipe_fd):
+        """
+        Reads bytes from a pipe and returns a character string.  If nothing is
+        read, or if there is an error, an empty string is returned.
+
+        pipe_fd - Pipe file descriptor to read
+        """
+        try:
+            data = os.read(pipe_fd, 16384)
+            # Make sure we have a string
+            if (data is None):
+                data = ""
+            else:
+                data = str(data)
+        except OSError:
+            data = ""
+
+        return data
+
+    def runCommand(self, params, wait=1):
+        """
+        This method runs a command and returns a tuple: (returncode, stdout, stderr)
+        """
+        ## @todo: Convert this into generic method and reuse it in dhcp4 and dhcp6
+
+        print("Running command: %s" % (" ".join(params)))
+
+        # redirect stdout to a pipe so we can check that our
+        # process spawning is doing the right thing with stdout
+        self.stdout_old = os.dup(sys.stdout.fileno())
+        self.stdout_pipes = os.pipe()
+        os.dup2(self.stdout_pipes[1], sys.stdout.fileno())
+        os.close(self.stdout_pipes[1])
+
+        # do the same trick for stderr:
+        self.stderr_old = os.dup(sys.stderr.fileno())
+        self.stderr_pipes = os.pipe()
+        os.dup2(self.stderr_pipes[1], sys.stderr.fileno())
+        os.close(self.stderr_pipes[1])
+
+        # note that we use dup2() to restore the original stdout
+        # to the main program ASAP in each test... this prevents
+        # hangs reading from the child process (as the pipe is only
+        # open in the child), and also insures nice pretty output
+
+        pi = ProcessInfo('Test Process', params)
+        pi.spawn()
+        time.sleep(wait)
+        os.dup2(self.stdout_old, sys.stdout.fileno())
+        os.dup2(self.stderr_old, sys.stderr.fileno())
+        self.assertNotEqual(pi.process, None)
+        self.assertTrue(type(pi.pid) is int)
+
+        # Set non-blocking read on pipes. Process may not print anything
+        # on specific output and the we would hang without this.
+        fd = self.stdout_pipes[0]
+        fl = fcntl.fcntl(fd, fcntl.F_GETFL)
+        fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
+
+        fd = self.stderr_pipes[0]
+        fl = fcntl.fcntl(fd, fcntl.F_GETFL)
+        fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
+
+        # As we don't know how long the subprocess will take to start and
+        # produce output, we'll loop and sleep for 250 ms between each
+        # iteration.  To avoid an infinite loop, we'll loop for a maximum
+        # of five seconds: that should be enough.
+        for count in range(20):
+            # Read something from stderr and stdout (these reads don't block).
+            output = self.readPipe(self.stdout_pipes[0])
+            error  = self.readPipe(self.stderr_pipes[0])
+
+            # If the process has already exited, or if it has output something,
+            # quit the loop now.
+            if pi.process.poll() is not None or len(error) > 0 or len(output) > 0:
+                break
+
+            # Process still running, try again in 250 ms.
+            time.sleep(0.25)
+
+        # Exited loop, kill the process if it is still running
+        if pi.process.poll() is None:
+            try:
+                pi.process.terminate()
+            except OSError:
+                print("Ignoring failed kill attempt. Process is dead already.")
+
+        # call this to get returncode, process should be dead by now
+        rc = pi.process.wait()
+
+        # Clean up our stdout/stderr munging.
+        os.dup2(self.stdout_old, sys.stdout.fileno())
+        os.close(self.stdout_old)
+        os.close(self.stdout_pipes[0])
+
+        os.dup2(self.stderr_old, sys.stderr.fileno())
+        os.close(self.stderr_old)
+        os.close(self.stderr_pipes[0])
+
+        # Free up resources (file descriptors) from the ProcessInfo object
+        # TODO: For some reason, this gives an error if the process has ended,
+        #       although it does cause all descriptors still allocated to the
+        #       object to be freed.
+        pi = None
+
+        print ("Process finished, return code=%d, stdout=%d bytes, stderr=%d bytes"
+               % (rc, len(output), len(error)) )
+
+        return (rc, output, error)
+
+    def test_alive(self):
+        print("Note: Simple test to verify that D2 server can be started.")
+        # note that "-s" for stand alone is necessary in order to flush the log output
+        # soon enough to catch it.
+        (returncode, output, error) = self.runCommand(["../b10-d2", "-s"])
+        output_text = str(output) + str(error)
+        self.assertEqual(output_text.count("D2_STARTING"), 1)
+
+if __name__ == '__main__':
+    unittest.main()

+ 31 - 0
src/bin/d2/tests/d2_unittests.cc

@@ -0,0 +1,31 @@
+// Copyright (C) 2013 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.
+
+#include <log/logger_support.h>
+#include <d2/d2_log.h>
+#include <gtest/gtest.h>
+
+int
+main(int argc, char* argv[]) {
+
+    ::testing::InitGoogleTest(&argc, argv);
+
+    // See the documentation of the B10_* environment variables in
+    // src/lib/log/README for info on how to tweak logging
+    isc::log::initLogger();
+
+    int result = RUN_ALL_TESTS();
+
+    return (result);
+}