Commit 392c5ec5 authored by Thomas Markwalder's avatar Thomas Markwalder
Browse files

[master] Merge branch 'trac2954', this adds dhcp-ddns process to

the source tree.
parents aa528462 0dcc4f4f
......@@ -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.])
fi
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)
# 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/dhcp4/Makefile
src/bin/dhcp4/tests/Makefile
src/bin/d2/Makefile
src/bin/d2/tests/Makefile
src/bin/resolver/Makefile
src/bin/resolver/tests/Makefile
src/bin/resolver/bench/Makefile
......@@ -1384,6 +1383,7 @@ AC_OUTPUT([doc/version.ent
src/bin/auth/gen-statisticsitems.py.pre
src/bin/dhcp4/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/lib/config/tests/data_def_unittests_config.h
src/lib/python/isc/config/tests/config_test
......
......@@ -689,6 +689,7 @@ INPUT = ../src/lib/exceptions \
../src/lib/dhcp \
../src/lib/dhcpsrv \
../src/bin/dhcp4 \
../src/bin/d2 \
../tests/tools/perfdhcp \
devel
......
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
check-recursive: all-recursive
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
<!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:
-->
{
"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
}
]
}
]
}
}
// 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
// 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
# 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.
// 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);
}
// 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"
PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
PYTESTS = d2_test.py
EXTRA_DIST = $(PYTESTS)
# Explicitly specify paths to dynamic libraries required by loadable python
# modules. That is required on Mac OS systems. Otherwise we will get exception
# about python not being able to load liblog library.
LIBRARY_PATH_PLACEHOLDER =
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/util/threads/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/util/io/.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:
for pytest in $(PYTESTS) ; do \
echo Running test: $$pytest ; \
PYTHONPATH=$(COMMON_PYTHON_PATH):$(abs_top_srcdir)/src/bin:$(abs_top_builddir)/src/bin/bind10:$(abs_top_builddir)/src/lib/util/io/.libs \
B10_LOCKFILE_DIR_FROM_BUILD=$(abs_top_builddir) \
$(LIBRARY_PATH_PLACEHOLDER) \
$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
done
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += -I$(top_builddir)/src/bin # for generated spec_config.h header
AM_CPPFLAGS += -I$(top_srcdir)/src/bin
AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/asiolink
AM_CPPFLAGS += $(BOOST_INCLUDES)
AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(abs_top_srcdir)/src/lib/testutils/testdata\"
AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/bin/d2/tests\"
AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
CLEANFILES = $(builddir)/interfaces.txt $(builddir)/logger_lockfile
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
TESTS_ENVIRONMENT = \
$(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
TESTS =
if HAVE_GTEST
TESTS += d2_unittests
d2_unittests_SOURCES = ../d2_log.h ../d2_log.cc
d2_unittests_SOURCES += d2_unittests.cc
nodist_d2_unittests_SOURCES = ../d2_messages.h ../d2_messages.cc
d2_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
d2_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
d2_unittests_LDADD = $(GTEST_LDADD)
d2_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
d2_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
endif
noinst_PROGRAMS = $(TESTS)
# 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])