BIND 10 master, updated. e79153fe56e7d514bd2ddf70450058e863c72d51 Changelog for #615
BIND 10 source code commits
bind10-changes at lists.isc.org
Tue Mar 15 08:25:30 UTC 2011
The branch, master has been updated
via e79153fe56e7d514bd2ddf70450058e863c72d51 (commit)
via 5514dd78f2d61a222f3069fc94723ca33fb3200b (commit)
via 7a3dc628e96dd7b5201a8a1d3851992ea8d325ce (commit)
via 1e67f2cbd82e555241a366d5b93a7a6ec52c7921 (commit)
via 170485efd4eb6cb6ba6af78d62be71b2354befd8 (commit)
via 5874ea28a5e9a3af38fc15c53bcf9d0690680e6c (commit)
via 4fd1b4c0f03f01b2fb085dae50455f6746b435c9 (commit)
via 691a4a2f4e82d52d313e67ddd9b1e5480226fefe (commit)
via 52247fe2ac1e071d95b3333d3c0cea73a0429399 (commit)
via dcaab4f4a892d1ab0e9e2c246282066891b2ffcb (commit)
via 02d45b17f160bd3662ee765147debe770c6d3faa (commit)
via fc26c7396d98fa84a8f057cc409303f911792365 (commit)
via 9dcb53261abe3c16324155fbc4c3436100b9e2ee (commit)
via e33f9a6d1009753b2f02b43e43da1014b0df1964 (commit)
via 07c01a7a90476fd6b90659bf809e7135ce26cff2 (commit)
via a1d7f70e7c660e847fb388c6f17d6709c93fe8e2 (commit)
via 96e55aef179874427ea28641316dd145fbd98175 (commit)
via ccdce3bab3f04bade1e92e66e3929ffd0db97f0b (commit)
via 79155a51eb422813900332ad1582ed5964d70f5c (commit)
via d686e3ada2141094413e756d601d2e727fb6f760 (commit)
via d0dcd91d39a438d5a18e0726251e1a93212143ca (commit)
via b32ea06f28de94a8ec779385d5e86374e81c023d (commit)
via 1faf02bda80053ddb2f815466d0372a2eeb6c08c (commit)
via 9e782794969ab034eb92dca6a8d5ee8f518ccc95 (commit)
from cd620bf3e4315d693582f25538b3bb71941a42e5 (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 e79153fe56e7d514bd2ddf70450058e863c72d51
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Tue Mar 15 09:24:52 2011 +0100
Changelog for #615
commit 5514dd78f2d61a222f3069fc94723ca33fb3200b
Merge: cd620bf3e4315d693582f25538b3bb71941a42e5 7a3dc628e96dd7b5201a8a1d3851992ea8d325ce
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Tue Mar 15 09:18:31 2011 +0100
Merge branch 'work/configuration'
commit 7a3dc628e96dd7b5201a8a1d3851992ea8d325ce
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Mon Mar 14 19:52:26 2011 +0100
[trac615] Eliminate hardcoded values
They need to be put to the test file, if they are not default values of
parameters.
commit 1e67f2cbd82e555241a366d5b93a7a6ec52c7921
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Mon Mar 14 17:33:26 2011 +0100
[trac615] Small cleanups
* A variable name
* Clarification of man pages
commit 170485efd4eb6cb6ba6af78d62be71b2354befd8
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Fri Mar 11 12:37:23 2011 +0100
[trac615] Unification of test parsers
Not directly related to this ticket, but master recently create a
private version of library test class this branch already has.
commit 5874ea28a5e9a3af38fc15c53bcf9d0690680e6c
Merge: 4fd1b4c0f03f01b2fb085dae50455f6746b435c9 11889ab357ea40764683e4be03bcc27a4ab6bb04
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Fri Mar 11 12:31:52 2011 +0100
Merge branch 'master' into work/configuration
Conflicts:
src/bin/bind10/bind10.py.in
src/bin/bind10/tests/bind10_test.py.in
commit 4fd1b4c0f03f01b2fb085dae50455f6746b435c9
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Fri Mar 11 12:03:20 2011 +0100
[trac615] Clarify man page
commit 691a4a2f4e82d52d313e67ddd9b1e5480226fefe
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Fri Mar 11 12:04:25 2011 +0100
[trac615] Code cleanups
- Less hardcoding of values
- Tests of missing argument values
- "args" instead of "opts" for argument values
- Some documentation updates
commit 52247fe2ac1e071d95b3333d3c0cea73a0429399
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Fri Mar 11 12:01:50 2011 +0100
[trac615] Unify config param to -c
commit dcaab4f4a892d1ab0e9e2c246282066891b2ffcb
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Thu Mar 10 11:43:10 2011 -0800
[trac615] minor editorial fixes.
- remove ' ' around '=' in parameter listing (style guideline)
- add a new line for readability
- typo in doc
commit 02d45b17f160bd3662ee765147debe770c6d3faa
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Wed Mar 9 20:25:02 2011 +0100
[trac615] Pass cmdctl port trough
commit fc26c7396d98fa84a8f057cc409303f911792365
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Wed Mar 9 19:57:06 2011 +0100
[trac615] Parsing of port for cmdctl
commit 9dcb53261abe3c16324155fbc4c3436100b9e2ee
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Tue Mar 8 17:32:20 2011 +0100
[trac615] Man pages for config files
commit e33f9a6d1009753b2f02b43e43da1014b0df1964
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Mon Mar 7 23:41:44 2011 +0100
[trac615] Prepagate corectly trough config manager
commit 07c01a7a90476fd6b90659bf809e7135ce26cff2
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Mon Mar 7 21:29:09 2011 +0100
[trac615] Pass the config options to cfgmgr
Any idea how to reasonably test this? Boss and it's tests seem to be
written in test-unfriendly way for this :-(.
commit a1d7f70e7c660e847fb388c6f17d6709c93fe8e2
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Mon Mar 7 20:55:19 2011 +0100
[trac615] Check even short opts for cfgmgr
commit 96e55aef179874427ea28641316dd145fbd98175
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Mon Mar 7 20:53:48 2011 +0100
[trac615] Parsing of --config-file and --data-path for boss
commit ccdce3bab3f04bade1e92e66e3929ffd0db97f0b
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Mon Mar 7 20:50:47 2011 +0100
[trac615] Tests for boss parsing args
commit 79155a51eb422813900332ad1582ed5964d70f5c
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Mon Mar 7 19:47:59 2011 +0100
[trac615] Take parsing of args to a function
The parsing is taken out so it can be tested independently on the rest.
We don't need to run the main function now.
commit d686e3ada2141094413e756d601d2e727fb6f760
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Fri Mar 4 11:09:12 2011 +0100
[trac615] Pass options to the manager
commit d0dcd91d39a438d5a18e0726251e1a93212143ca
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Fri Mar 4 10:59:14 2011 +0100
[trac615] Parser of args
commit b32ea06f28de94a8ec779385d5e86374e81c023d
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Thu Mar 3 19:19:26 2011 +0100
[trac615] Tests for parsing args
commit 1faf02bda80053ddb2f815466d0372a2eeb6c08c
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Thu Mar 3 18:57:00 2011 +0100
[trac615] Don't hurt absolute names
commit 9e782794969ab034eb92dca6a8d5ee8f518ccc95
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Thu Mar 3 18:47:56 2011 +0100
[trac615] Test absolute filename for cfgmgr
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 7 ++
configure.ac | 1 +
src/bin/bind10/bind10.py.in | 102 ++++++++++++++------
src/bin/bind10/bind10.xml | 27 +++++
src/bin/bind10/tests/bind10_test.py.in | 54 ++++++++++-
src/bin/bindctl/tests/bindctl_test.py | 20 +----
src/bin/cfgmgr/b10-cfgmgr.py.in | 19 ++++-
src/bin/cfgmgr/b10-cfgmgr.xml | 45 ++++++----
src/bin/cfgmgr/tests/b10-cfgmgr_test.py.in | 66 +++++++++++++-
src/lib/python/isc/Makefile.am | 2 +-
src/lib/python/isc/config/cfgmgr.py | 66 ++++++++-----
src/lib/python/isc/config/tests/cfgmgr_test.py | 40 +++++++--
src/lib/python/isc/testutils/Makefile.am | 1 +
src/lib/python/isc/testutils/README | 3 +
.../python/isc/testutils/__init__.py} | 7 +-
.../python/isc/testutils/parse_args.py} | 18 +++-
16 files changed, 373 insertions(+), 105 deletions(-)
create mode 100644 src/lib/python/isc/testutils/Makefile.am
create mode 100644 src/lib/python/isc/testutils/README
copy src/{bin/stats/tests/isc/util/process.py => lib/python/isc/testutils/__init__.py} (84%)
copy src/{bin/stats/tests/isc/util/process.py => lib/python/isc/testutils/parse_args.py} (60%)
-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index 09293ab..c7ff9ac 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+ 202. [func] vorner
+ It is possible to specify a different directory where we look for
+ configuration files (by -p) and different configuration file to use (-c).
+ Also, it is possible to specify the port on which cmdctl should listen
+ (--cmdctl-port).
+ (Trac #615, git 5514dd78f2d61a222f3069fc94723ca33fb3200b)
+
201. [bug] jerry
src/bin/bindctl: bindctl doesn't show traceback on shutdown.
(Trac #588, git 662e99ef050d98e86614c4443326568a0b5be437)
diff --git a/configure.ac b/configure.ac
index acc7628..b93fdc7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -663,6 +663,7 @@ AC_CONFIG_FILES([Makefile
src/lib/python/isc/net/tests/Makefile
src/lib/python/isc/notify/Makefile
src/lib/python/isc/notify/tests/Makefile
+ src/lib/python/isc/testutils/Makefile
src/lib/config/Makefile
src/lib/config/tests/Makefile
src/lib/config/tests/testdata/Makefile
diff --git a/src/bin/bind10/bind10.py.in b/src/bin/bind10/bind10.py.in
index ce6e523..9cdf6f0 100755
--- a/src/bin/bind10/bind10.py.in
+++ b/src/bin/bind10/bind10.py.in
@@ -194,14 +194,21 @@ class CChannelConnectError(Exception): pass
class BoB:
"""Boss of BIND class."""
- def __init__(self, msgq_socket_file=None, nocache=False, verbose=False,
- setuid=None, username=None):
+ def __init__(self, msgq_socket_file=None, data_path=None,
+ config_filename=None, nocache=False, verbose=False, setuid=None,
+ username=None, cmdctl_port=None):
"""
Initialize the Boss of BIND. This is a singleton (only one can run).
The msgq_socket_file specifies the UNIX domain socket file that the
msgq process listens on. If verbose is True, then the boss reports
what it is doing.
+
+ Data path and config filename are passed trough to config manager
+ (if provided) and specify the config file to be used.
+
+ The cmdctl_port is passed to cmdctl and specify on which port it
+ should listen.
"""
self.cc_session = None
self.ccs = None
@@ -219,6 +226,9 @@ class BoB:
self.uid = setuid
self.username = username
self.verbose = verbose
+ self.data_path = data_path
+ self.config_filename = config_filename
+ self.cmdctl_port = cmdctl_port
def config_handler(self, new_config):
# If this is initial update, don't do anything now, leave it to startup
@@ -390,7 +400,12 @@ class BoB:
Starts the configuration manager process
"""
self.log_starting("b10-cfgmgr")
- bind_cfgd = ProcessInfo("b10-cfgmgr", ["b10-cfgmgr"],
+ args = ["b10-cfgmgr"]
+ if self.data_path is not None:
+ args.append("--data-path=" + self.data_path)
+ if self.config_filename is not None:
+ args.append("--config-filename=" + self.config_filename)
+ bind_cfgd = ProcessInfo("b10-cfgmgr", args,
c_channel_env, uid=self.uid,
username=self.username)
self.processes[bind_cfgd.pid] = bind_cfgd
@@ -500,8 +515,13 @@ class BoB:
self.start_simple("b10-stats", c_channel_env)
def start_cmdctl(self, c_channel_env):
- # XXX: we hardcode port 8080
- self.start_simple("b10-cmdctl", c_channel_env, 8080)
+ """
+ Starts the command control process
+ """
+ args = ["b10-cmdctl"]
+ if self.cmdctl_port is not None:
+ args.append("--port=" + str(self.cmdctl_port))
+ self.start_process("b10-cmdctl", args, c_channel_env, self.cmdctl_port)
def start_all_processes(self):
"""
@@ -785,6 +805,50 @@ def process_rename(option, opt_str, value, parser):
"""Function that renames the process if it is requested by a option."""
isc.util.process.rename(value)
+def parse_args(args=sys.argv[1:], Parser=OptionParser):
+ """
+ Function for parsing command line arguments. Returns the
+ options object from OptionParser.
+ """
+ parser = Parser(version=VERSION)
+ parser.add_option("-m", "--msgq-socket-file", dest="msgq_socket_file",
+ type="string", default=None,
+ help="UNIX domain socket file the b10-msgq daemon will use")
+ parser.add_option("-n", "--no-cache", action="store_true", dest="nocache",
+ default=False, help="disable hot-spot cache in authoritative DNS server")
+ parser.add_option("-u", "--user", dest="user", type="string", default=None,
+ help="Change user after startup (must run as root)")
+ parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
+ help="display more about what is going on")
+ parser.add_option("--pretty-name", type="string", action="callback",
+ callback=process_rename,
+ help="Set the process name (displayed in ps, top, ...)")
+ parser.add_option("-c", "--config-file", action="store",
+ dest="config_file", default=None,
+ help="Configuration database filename")
+ parser.add_option("-p", "--data-path", dest="data_path",
+ help="Directory to search for configuration files",
+ default=None)
+ parser.add_option("--cmdctl-port", dest="cmdctl_port", type="int",
+ default=None, help="Port of command control")
+ parser.add_option("--pid-file", dest="pid_file", type="string",
+ default=None,
+ help="file to dump the PID of the BIND 10 process")
+
+ (options, args) = parser.parse_args(args)
+
+ if options.cmdctl_port is not None:
+ try:
+ isc.net.parse.port_parse(options.cmdctl_port)
+ except ValueError as e:
+ parser.error(e)
+
+ if args:
+ parser.print_help()
+ sys.exit(1)
+
+ return options
+
def dump_pid(pid_file):
"""
Dump the PID of the current process to the specified file. If the given
@@ -814,33 +878,14 @@ def unlink_pid_file(pid_file):
if error.errno is not errno.ENOENT:
raise
+
def main():
global options
global boss_of_bind
# Enforce line buffering on stdout, even when not a TTY
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), line_buffering=True)
- # Parse any command-line options.
- parser = OptionParser(version=VERSION)
- parser.add_option("-m", "--msgq-socket-file", dest="msgq_socket_file",
- type="string", default=None,
- help="UNIX domain socket file the b10-msgq daemon will use")
- parser.add_option("-n", "--no-cache", action="store_true", dest="nocache",
- default=False, help="disable hot-spot cache in authoritative DNS server")
- parser.add_option("-u", "--user", dest="user", type="string", default=None,
- help="Change user after startup (must run as root)")
- parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
- help="display more about what is going on")
- parser.add_option("--pretty-name", type="string", action="callback",
- callback=process_rename,
- help="Set the process name (displayed in ps, top, ...)")
- parser.add_option("--pid-file", dest="pid_file", type="string",
- default=None,
- help="file to dump the PID of the BIND 10 process")
- (options, args) = parser.parse_args()
- if args:
- parser.print_help()
- sys.exit(1)
+ options = parse_args()
# Check user ID.
setuid = None
@@ -890,8 +935,9 @@ def main():
signal.signal(signal.SIGPIPE, signal.SIG_IGN)
# Go bob!
- boss_of_bind = BoB(options.msgq_socket_file, options.nocache,
- options.verbose, setuid, username)
+ boss_of_bind = BoB(options.msgq_socket_file, options.data_path,
+ options.config_file, options.nocache, options.verbose,
+ setuid, username, options.cmdctl_port)
startup_result = boss_of_bind.startup()
if startup_result:
sys.stderr.write("[bind10] Error on startup: %s\n" % startup_result)
diff --git a/src/bin/bind10/bind10.xml b/src/bin/bind10/bind10.xml
index eb237ab..6331503 100644
--- a/src/bin/bind10/bind10.xml
+++ b/src/bin/bind10/bind10.xml
@@ -48,6 +48,8 @@
<arg><option>-n</option></arg>
<arg><option>-u <replaceable>user</replaceable></option></arg>
<arg><option>-v</option></arg>
+ <arg><option>-c<replaceable>config-filename</replaceable></option></arg>
+ <arg><option>-p<replaceable>data_path</replaceable></option></arg>
<arg><option>--msgq-socket-file <replaceable>file</replaceable></option></arg>
<arg><option>--no-cache</option></arg>
<arg><option>--user <replaceable>user</replaceable></option></arg>
@@ -80,6 +82,31 @@
<para>The arguments are as follows:</para>
<variablelist>
+ <varlistentry>
+ <term>
+ <option>-c</option><replaceable>config-filename</replaceable>,
+ <option>--config-file</option> <replaceable>config-filename</replaceable>
+ </term>
+ <listitem>
+ <para>The configuration filename to use. Can be either absolute or
+ relative to data path. In case it is absolute, value of data path is
+ not considered.</para>
+ <para>Defaults to b10-config.db.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>-p</option><replaceable>data-path</replaceable>,
+ <option>--data-path</option> <replaceable>data-path</replaceable>
+ </term>
+ <listitem>
+ <para>The path where BIND 10 programs look for various data files.
+ Currently only b10-cfgmgr uses it to locate the configuration file,
+ but the usage might be extended for other programs and other types
+ of files.</para>
+ </listitem>
+ </varlistentry>
<varlistentry>
<term><option>-m</option> <replaceable>file</replaceable>,
diff --git a/src/bin/bind10/tests/bind10_test.py.in b/src/bin/bind10/tests/bind10_test.py.in
index 0603443..a53df1a 100644
--- a/src/bin/bind10/tests/bind10_test.py.in
+++ b/src/bin/bind10/tests/bind10_test.py.in
@@ -1,4 +1,4 @@
-from bind10 import ProcessInfo, BoB, dump_pid, unlink_pid_file
+from bind10 import ProcessInfo, BoB, parse_args, dump_pid, unlink_pid_file
# XXX: environment tests are currently disabled, due to the preprocessor
# setup that we have now complicating the environment
@@ -9,6 +9,7 @@ import os
import signal
import socket
from isc.net.addr import IPAddr
+from isc.testutils.parse_args import TestOptParser, OptsError
class TestProcessInfo(unittest.TestCase):
def setUp(self):
@@ -412,6 +413,57 @@ class TestStartStopProcessesBob(unittest.TestCase):
bob.config_handler({'start_auth': True, 'start_resolver': True})
+class TestParseArgs(unittest.TestCase):
+ """
+ This tests parsing of arguments of the bind10 master process.
+ """
+ #TODO: Write tests for the original parsing, bad options, etc.
+ def test_no_opts(self):
+ """
+ Test correct default values when no options are passed.
+ """
+ options = parse_args([], TestOptParser)
+ self.assertEqual(None, options.data_path)
+ self.assertEqual(None, options.config_file)
+ self.assertEqual(None, options.cmdctl_port)
+
+ def test_data_path(self):
+ """
+ Test it can parse the data path.
+ """
+ self.assertRaises(OptsError, parse_args, ['-p'], TestOptParser)
+ self.assertRaises(OptsError, parse_args, ['--data-path'],
+ TestOptParser)
+ options = parse_args(['-p', '/data/path'], TestOptParser)
+ self.assertEqual('/data/path', options.data_path)
+ options = parse_args(['--data-path=/data/path'], TestOptParser)
+ self.assertEqual('/data/path', options.data_path)
+
+ def test_config_filename(self):
+ """
+ Test it can parse the config switch.
+ """
+ self.assertRaises(OptsError, parse_args, ['-c'], TestOptParser)
+ self.assertRaises(OptsError, parse_args, ['--config-file'],
+ TestOptParser)
+ options = parse_args(['-c', 'config-file'], TestOptParser)
+ self.assertEqual('config-file', options.config_file)
+ options = parse_args(['--config-file=config-file'], TestOptParser)
+ self.assertEqual('config-file', options.config_file)
+
+ def test_cmdctl_port(self):
+ """
+ Test it can parse the command control port.
+ """
+ self.assertRaises(OptsError, parse_args, ['--cmdctl-port=abc'],
+ TestOptParser)
+ self.assertRaises(OptsError, parse_args, ['--cmdctl-port=100000000'],
+ TestOptParser)
+ self.assertRaises(OptsError, parse_args, ['--cmdctl-port'],
+ TestOptParser)
+ options = parse_args(['--cmdctl-port=1234'], TestOptParser)
+ self.assertEqual(1234, options.cmdctl_port)
+
class TestPIDFile(unittest.TestCase):
def setUp(self):
self.pid_file = '@builddir@' + os.sep + 'bind10.pid'
diff --git a/src/bin/bindctl/tests/bindctl_test.py b/src/bin/bindctl/tests/bindctl_test.py
index 148bf3a..0635b32 100644
--- a/src/bin/bindctl/tests/bindctl_test.py
+++ b/src/bin/bindctl/tests/bindctl_test.py
@@ -26,6 +26,7 @@ import getpass
from optparse import OptionParser
from isc.config.config_data import ConfigData, MultiConfigData
from isc.config.module_spec import ModuleSpec
+from isc.testutils.parse_args import TestOptParser, OptsError
from bindctl_main import set_bindctl_options
from bindctl import cmdparse
from bindctl import bindcmd
@@ -452,23 +453,8 @@ class TestBindCmdInterpreter(unittest.TestCase):
class TestCommandLineOptions(unittest.TestCase):
- class FakeParserError(Exception):
- """An exception thrown from FakeOptionParser on parser error.
- """
- pass
-
- class FakeOptionParser(OptionParser):
- """This fake class emulates the OptionParser class with customized
- error handling for the convenient of tests.
- """
- def __init__(self):
- OptionParser.__init__(self)
-
- def error(self, msg):
- raise TestCommandLineOptions.FakeParserError
-
def setUp(self):
- self.parser = self.FakeOptionParser()
+ self.parser = TestOptParser()
set_bindctl_options(self.parser)
def test_csv_file_dir(self):
@@ -481,7 +467,7 @@ class TestCommandLineOptions(unittest.TestCase):
self.assertEqual('some_dir', options.csv_file_dir)
# missing option arg; should trigger parser error.
- self.assertRaises(self.FakeParserError, self.parser.parse_args,
+ self.assertRaises(OptsError, self.parser.parse_args,
['--csv-file-dir'])
if __name__== "__main__":
diff --git a/src/bin/cfgmgr/b10-cfgmgr.py.in b/src/bin/cfgmgr/b10-cfgmgr.py.in
index e37ec48..5355582 100755
--- a/src/bin/cfgmgr/b10-cfgmgr.py.in
+++ b/src/bin/cfgmgr/b10-cfgmgr.py.in
@@ -22,6 +22,7 @@ from isc.cc import SessionError
import isc.util.process
import signal
import os
+from optparse import OptionParser
isc.util.process.rename()
@@ -41,18 +42,34 @@ if "B10_FROM_SOURCE" in os.environ:
else:
PREFIX = "@prefix@"
DATA_PATH = "@localstatedir@/@PACKAGE@".replace("${prefix}", PREFIX)
+DEFAULT_CONFIG_FILE = "b10-config.db"
cm = None
+def parse_options(args=sys.argv[1:], Parser=OptionParser):
+ parser = Parser()
+ parser.add_option("-p", "--data-path", dest="data_path",
+ help="Directory to search for configuration files " +
+ "(default=" + DATA_PATH + ")", default=DATA_PATH)
+ parser.add_option("-c", "--config-filename", dest="config_file",
+ help="Configuration database filename " +
+ "(default=" + DEFAULT_CONFIG_FILE + ")",
+ default=DEFAULT_CONFIG_FILE)
+ (options, args) = parser.parse_args(args)
+ if args:
+ parser.error("No non-option arguments allowed")
+ return options
+
def signal_handler(signal, frame):
global cm
if cm:
cm.running = False
def main():
+ options = parse_options()
global cm
try:
- cm = ConfigManager(DATA_PATH)
+ cm = ConfigManager(options.data_path, options.config_file)
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
cm.read_config()
diff --git a/src/bin/cfgmgr/b10-cfgmgr.xml b/src/bin/cfgmgr/b10-cfgmgr.xml
index 9505eee..08a6a97 100644
--- a/src/bin/cfgmgr/b10-cfgmgr.xml
+++ b/src/bin/cfgmgr/b10-cfgmgr.xml
@@ -41,16 +41,13 @@
</copyright>
</docinfo>
-<!--
<refsynopsisdiv>
<cmdsynopsis>
- <command></command>
- <arg><option></option></arg>
- <arg choice="opt"></arg>
- <arg choice="opt"></arg>
+ <command>b10-cfgmgr</command>
+ <arg><option>-c<replaceable>config-filename</replaceable></option></arg>
+ <arg><option>-p<replaceable>data_path</replaceable></option></arg>
</cmdsynopsis>
</refsynopsisdiv>
--->
<refsect1>
<title>DESCRIPTION</title>
@@ -93,24 +90,38 @@
</para>
</refsect1>
-<!--
<refsect1>
<title>ARGUMENTS</title>
- <para>
- <orderedlist numeration="loweralpha">
+
+ <para>The arguments are as follows:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term>
+ <option>-c</option><replaceable>config-filename</replaceable>,
+ <option>--config-filename</option> <replaceable>config-filename</replaceable>
+ </term>
<listitem>
- <para>
- </para>
+ <para>The configuration database filename to use. Can be either
+ absolute or relative to data path.</para>
+ <para>Defaults to b10-config.db</para>
</listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>-p</option><replaceable>data-path</replaceable>,
+ <option>--data-path</option> <replaceable>data-path</replaceable>
+ </term>
<listitem>
- <para>
- </para>
+ <para>The path where BIND 10 looks for files. The
+ configuration file is looked for here, if it is relative. If it is
+ absolute, the path is ignored.</para>
</listitem>
- </orderedlist>
- </para>
-
+ </varlistentry>
+ </variablelist>
</refsect1>
--->
+
<refsect1>
<title>FILES</title>
<!-- TODO: fix path -->
diff --git a/src/bin/cfgmgr/tests/b10-cfgmgr_test.py.in b/src/bin/cfgmgr/tests/b10-cfgmgr_test.py.in
index 8847b18..037a106 100644
--- a/src/bin/cfgmgr/tests/b10-cfgmgr_test.py.in
+++ b/src/bin/cfgmgr/tests/b10-cfgmgr_test.py.in
@@ -20,9 +20,10 @@
import unittest
import os
import sys
+from isc.testutils.parse_args import OptsError, TestOptParser
class MyConfigManager:
- def __init__(self, path):
+ def __init__(self, path, filename):
self._path = path
self.read_config_called = False
self.notify_boss_called = False
@@ -88,6 +89,69 @@ class TestConfigManagerStartup(unittest.TestCase):
sys.modules.pop("b10-cfgmgr")
+class TestParseArgs(unittest.TestCase):
+ """
+ Test for the parsing of command line arguments. We provide a different
+ array to parse instead.
+ """
+
+ def test_defaults(self):
+ """
+ Test the default values when no options are provided.
+ """
+ # Pass it empty array, not our arguments
+ b = __import__("b10-cfgmgr")
+ parsed = b.parse_options([], TestOptParser)
+ self.assertEqual(b.DATA_PATH, parsed.data_path)
+ self.assertEqual(b.DEFAULT_CONFIG_FILE, parsed.config_file)
+
+ def test_wrong_args(self):
+ """
+ Test it fails when we pass invalid option.
+ """
+ b = __import__("b10-cfgmgr")
+ self.assertRaises(OptsError, b.parse_options, ['--wrong-option'],
+ TestOptParser)
+
+ def test_not_arg(self):
+ """
+ Test it fails when there's an argument that's not option
+ (eg. without -- at the beginning).
+ """
+ b = __import__("b10-cfgmgr")
+ self.assertRaises(OptsError, b.parse_options, ['not-option'],
+ TestOptParser)
+
+ def test_datapath(self):
+ """
+ Test overwriting the data path.
+ """
+ b = __import__("b10-cfgmgr")
+ parsed = b.parse_options(['--data-path=/path'], TestOptParser)
+ self.assertEqual('/path', parsed.data_path)
+ self.assertEqual(b.DEFAULT_CONFIG_FILE, parsed.config_file)
+ parsed = b.parse_options(['-p', '/path'], TestOptParser)
+ self.assertEqual('/path', parsed.data_path)
+ self.assertEqual(b.DEFAULT_CONFIG_FILE, parsed.config_file)
+ self.assertRaises(OptsError, b.parse_options, ['-p'], TestOptParser)
+ self.assertRaises(OptsError, b.parse_options, ['--data-path'],
+ TestOptParser)
+
+ def test_db_filename(self):
+ """
+ Test setting the configuration database file.
+ """
+ b = __import__("b10-cfgmgr")
+ parsed = b.parse_options(['--config-filename=filename'],
+ TestOptParser)
+ self.assertEqual(b.DATA_PATH, parsed.data_path)
+ self.assertEqual("filename", parsed.config_file)
+ parsed = b.parse_options(['-c', 'filename'], TestOptParser)
+ self.assertEqual(b.DATA_PATH, parsed.data_path)
+ self.assertEqual("filename", parsed.config_file)
+ self.assertRaises(OptsError, b.parse_options, ['-c'], TestOptParser)
+ self.assertRaises(OptsError, b.parse_options, ['--config-filename'],
+ TestOptParser)
if __name__ == '__main__':
unittest.main()
diff --git a/src/lib/python/isc/Makefile.am b/src/lib/python/isc/Makefile.am
index bda911b..7a54909 100644
--- a/src/lib/python/isc/Makefile.am
+++ b/src/lib/python/isc/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = datasrc cc config log net notify util
+SUBDIRS = datasrc cc config log net notify util testutils
python_PYTHON = __init__.py
diff --git a/src/lib/python/isc/config/cfgmgr.py b/src/lib/python/isc/config/cfgmgr.py
index e347f6a..8561378 100644
--- a/src/lib/python/isc/config/cfgmgr.py
+++ b/src/lib/python/isc/config/cfgmgr.py
@@ -44,25 +44,36 @@ class ConfigManagerData:
"""This class hold the actual configuration information, and
reads it from and writes it to persistent storage"""
- def __init__(self, data_path, file_name = "b10-config.db"):
+ def __init__(self, data_path, file_name):
"""Initialize the data for the configuration manager, and
set the version and path for the data store. Initializing
this does not yet read the database, a call to
- read_from_file is needed for that."""
+ read_from_file is needed for that.
+
+ In case the file_name is absolute, data_path is ignored
+ and the directory where the file_name lives is used instead.
+ """
self.data = {}
self.data['version'] = config_data.BIND10_CONFIG_DATA_VERSION
- self.data_path = data_path
- self.db_filename = data_path + os.sep + file_name
+ if os.path.isabs(file_name):
+ self.db_filename = file_name
+ self.data_path = os.path.dirname(file_name)
+ else:
+ self.db_filename = data_path + os.sep + file_name
+ self.data_path = data_path
+
+ def read_from_file(data_path, file_name):
+ """Read the current configuration found in the file file_name.
+ If file_name is absolute, data_path is ignored. Otherwise
+ we look for the file_name in data_path directory.
- def read_from_file(data_path, file_name = "b10-config.db"):
- """Read the current configuration found in the file at
- data_path. If the file does not exist, a
- ConfigManagerDataEmpty exception is raised. If there is a
- parse error, or if the data in the file has the wrong
- version, a ConfigManagerDataReadError is raised. In the first
- case, it is probably safe to log and ignore. In the case of
- the second exception, the best way is probably to report the
- error and stop loading the system."""
+ If the file does not exist, a ConfigManagerDataEmpty exception is
+ raised. If there is a parse error, or if the data in the file has
+ the wrong version, a ConfigManagerDataReadError is raised. In the
+ first case, it is probably safe to log and ignore. In the case of
+ the second exception, the best way is probably to report the error
+ and stop loading the system.
+ """
config = ConfigManagerData(data_path, file_name)
file = None
try:
@@ -142,20 +153,24 @@ class ConfigManagerData:
class ConfigManager:
"""Creates a configuration manager. The data_path is the path
- to the directory containing the b10-config.db file.
+ to the directory containing the configuraton file,
+ database_filename points to the configuration file.
If session is set, this will be used as the communication
channel session. If not, a new session will be created.
The ability to specify a custom session is for testing purposes
and should not be needed for normal usage."""
- def __init__(self, data_path, session = None):
+ def __init__(self, data_path, database_filename, session=None):
"""Initialize the configuration manager. The data_path string
is the path to the directory where the configuration is
- stored (in <data_path>/b10-config.db). Session is an optional
+ stored (in <data_path>/<database_filename> or in
+ <database_filename>, if it is absolute). The dabase_filename
+ is the config file to load. Session is an optional
cc-channel session. If this is not given, a new one is
- created"""
+ created."""
self.data_path = data_path
+ self.database_filename = database_filename
self.module_specs = {}
- self.config = ConfigManagerData(data_path)
+ self.config = ConfigManagerData(data_path, database_filename)
if session:
self.cc = session
else:
@@ -223,17 +238,18 @@ class ConfigManager:
return commands
def read_config(self):
- """Read the current configuration from the b10-config.db file
- at the path specificied at init()"""
+ """Read the current configuration from the file specificied at init()"""
try:
- self.config = ConfigManagerData.read_from_file(self.data_path)
+ self.config = ConfigManagerData.read_from_file(self.data_path,
+ self.\
+ database_filename)
except ConfigManagerDataEmpty:
# ok, just start with an empty config
- self.config = ConfigManagerData(self.data_path)
+ self.config = ConfigManagerData(self.data_path,
+ self.database_filename)
def write_config(self):
- """Write the current configuration to the b10-config.db file
- at the path specificied at init()"""
+ """Write the current configuration to the file specificied at init()"""
self.config.write_to_file()
def _handle_get_module_spec(self, cmd):
diff --git a/src/lib/python/isc/config/tests/cfgmgr_test.py b/src/lib/python/isc/config/tests/cfgmgr_test.py
index c992d0d..9534e14 100644
--- a/src/lib/python/isc/config/tests/cfgmgr_test.py
+++ b/src/lib/python/isc/config/tests/cfgmgr_test.py
@@ -27,9 +27,20 @@ class TestConfigManagerData(unittest.TestCase):
def setUp(self):
self.data_path = os.environ['CONFIG_TESTDATA_PATH']
self.writable_data_path = os.environ['CONFIG_WR_TESTDATA_PATH']
- self.config_manager_data = ConfigManagerData(self.writable_data_path)
+ self.config_manager_data = ConfigManagerData(self.writable_data_path,
+ file_name="b10-config.db")
self.assert_(self.config_manager_data)
+ def test_abs_file(self):
+ """
+ Test what happens if we give the config manager an absolute path.
+ It shouldn't append the data path to it.
+ """
+ abs_path = self.data_path + os.sep + "b10-config-imaginary.db"
+ data = ConfigManagerData(os.getcwd(), abs_path)
+ self.assertEqual(abs_path, data.db_filename)
+ self.assertEqual(self.data_path, data.data_path)
+
def test_init(self):
self.assertEqual(self.config_manager_data.data['version'],
config_data.BIND10_CONFIG_DATA_VERSION)
@@ -39,10 +50,10 @@ class TestConfigManagerData(unittest.TestCase):
self.writable_data_path + os.sep + "b10-config.db")
def test_read_from_file(self):
- ConfigManagerData.read_from_file(self.writable_data_path)
+ ConfigManagerData.read_from_file(self.writable_data_path, "b10-config.db")
self.assertRaises(ConfigManagerDataEmpty,
ConfigManagerData.read_from_file,
- "doesnotexist")
+ "doesnotexist", "b10-config.db")
self.assertRaises(ConfigManagerDataReadError,
ConfigManagerData.read_from_file,
self.data_path, "b10-config-bad1.db")
@@ -68,8 +79,8 @@ class TestConfigManagerData(unittest.TestCase):
# by equality of the .data element. If data_path or db_filename
# are different, but the contents are the same, it's still
# considered equal
- cfd1 = ConfigManagerData(self.data_path)
- cfd2 = ConfigManagerData(self.data_path)
+ cfd1 = ConfigManagerData(self.data_path, file_name="b10-config.db")
+ cfd2 = ConfigManagerData(self.data_path, file_name="b10-config.db")
self.assertEqual(cfd1, cfd2)
cfd2.data_path = "some/unknown/path"
self.assertEqual(cfd1, cfd2)
@@ -85,10 +96,25 @@ class TestConfigManager(unittest.TestCase):
self.data_path = os.environ['CONFIG_TESTDATA_PATH']
self.writable_data_path = os.environ['CONFIG_WR_TESTDATA_PATH']
self.fake_session = FakeModuleCCSession()
- self.cm = ConfigManager(self.writable_data_path, self.fake_session)
+ self.cm = ConfigManager(self.writable_data_path,
+ database_filename="b10-config.db",
+ session=self.fake_session)
self.name = "TestModule"
self.spec = isc.config.module_spec_from_file(self.data_path + os.sep + "/spec2.spec")
-
+
+ def test_paths(self):
+ """
+ Test data_path and database filename is passed trough to
+ underlying ConfigManagerData.
+ """
+ cm = ConfigManager("datapath", "filename", self.fake_session)
+ self.assertEqual("datapath" + os.sep + "filename",
+ cm.config.db_filename)
+ # It should preserve it while reading
+ cm.read_config()
+ self.assertEqual("datapath" + os.sep + "filename",
+ cm.config.db_filename)
+
def test_init(self):
self.assert_(self.cm.module_specs == {})
self.assert_(self.cm.data_path == self.writable_data_path)
diff --git a/src/lib/python/isc/testutils/Makefile.am b/src/lib/python/isc/testutils/Makefile.am
new file mode 100644
index 0000000..8f00a9b
--- /dev/null
+++ b/src/lib/python/isc/testutils/Makefile.am
@@ -0,0 +1 @@
+EXTRA_DIST = __init__.py parse_args.py
diff --git a/src/lib/python/isc/testutils/README b/src/lib/python/isc/testutils/README
new file mode 100644
index 0000000..c0389a8
--- /dev/null
+++ b/src/lib/python/isc/testutils/README
@@ -0,0 +1,3 @@
+This contains some shared test code for other modules and python processes.
+That's why it doesn't have its own test subdirectory and why it isn't
+installed.
diff --git a/src/lib/python/isc/testutils/__init__.py b/src/lib/python/isc/testutils/__init__.py
new file mode 100644
index 0000000..afcccf4
--- /dev/null
+++ b/src/lib/python/isc/testutils/__init__.py
@@ -0,0 +1,17 @@
+# Copyright (C) 2011 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.
+
+# Nothing here, really, it's just to tell python this directory is in
+# module hierarchy
diff --git a/src/lib/python/isc/testutils/parse_args.py b/src/lib/python/isc/testutils/parse_args.py
new file mode 100644
index 0000000..5d79137
--- /dev/null
+++ b/src/lib/python/isc/testutils/parse_args.py
@@ -0,0 +1,30 @@
+# Copyright (C) 2011 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 optparse import OptionParser
+
+class OptsError(Exception):
+ """To know when OptionParser would exit"""
+ pass
+
+class TestOptParser(OptionParser):
+ """
+ We define our own option parser to push into the parsing routine.
+ This one does not exit the whole application on error, it just raises
+ exception. It doesn't change anything else. The application uses the
+ stock one.
+ """
+ def error(self, message):
+ raise OptsError(message)
More information about the bind10-changes
mailing list