# HG changeset patch # User Tero Marttila # Date 1238694877 -10800 # Node ID e66102ab7048c3548d8322bc525da9dff23602f6 # Parent 2223ade4f25939eb343579a2bac5cadf39c82d7a fix up data.load_py, and make conf.File be a ConfObject itself - implement this for dhcp_conf diff -r 2223ade4f259 -r e66102ab7048 data.py --- a/data.py Thu Apr 02 20:19:18 2009 +0300 +++ b/data.py Thu Apr 02 20:54:37 2009 +0300 @@ -4,20 +4,13 @@ import imp -def load_py (path) : +def load_py (name, path) : """ - Load a python file from the given filesystem path, returning the module itself + Load a python file from the given filesystem path, returning the module itself. + + The "name" of the module must be given, it should be something sane and unique... """ - # XXX: what name to use? - name = "hosts" + # just load it and return + return imp.load_source(name, path) - # find the module - file, pathname, info = imp.find_module(name, [path]) - - # load it - module = imp.load_module(name, file, pathname, info) - - # ok - return module - diff -r 2223ade4f259 -r e66102ab7048 dhcp_conf.py --- a/dhcp_conf.py Thu Apr 02 20:19:18 2009 +0300 +++ b/dhcp_conf.py Thu Apr 02 20:54:37 2009 +0300 @@ -6,18 +6,43 @@ import itertools +class Comment (conf.ConfObject) : + """ + A comment, is, well, a comment :) + + Currently, comments are only one line, and look like the following: + "#" + """ + + def __init__ (self, comment) : + """ + @param comment the comment string + """ + + self.comment = comment + + def fmt_lines (self) : + """ + Yield a single line with the comment + """ + + yield "# %s" % (self.comment, ) + class Section (conf.ConfObject) : """ A section holds a list of params and a list of decls """ - def __init__ (self, params=None, decls=None) : + def __init__ (self, params=None, decls=None, comment=None) : """ If params/decls are given, those are the used as the initial contents of this section + + If a comment is given, then it will be formatted before the section's stuff """ self.params = params or [] self.decls = decls or [] + self.comment = comment def add_param (self, param) : """ @@ -41,11 +66,23 @@ for decl in decls : self.add_decl(decl) + def _fmt_comment (self) : + """ + Format our comment line + """ + + return "# %s" % (self.comment, ) + + def fmt_lines (self) : """ Format all of our params and decls, in that order """ + # comment? + if self.comment : + yield self._fmt_comment() + # then output each content line for stmt in itertools.chain(self.params, self.decls) : # skip Nones @@ -74,14 +111,11 @@ def __init__ (self, name, *args) : """ - The statement will be formatted like this: - [ [ ... ] ] ";" - Arguments given as None will be ignored. """ self.name = name - self.args = args + self.args = [arg for arg in args if arg is not None] def _fmt_arg (self, arg) : """ @@ -121,7 +155,7 @@ Formats the statement name/params as a single line, ignoring None """ - return "%s%s" % (self.name, (' ' + ' '.join(self._fmt_arg(a) for a in self.args if a is not None)) if self.args else '') + return "%s%s" % (self.name, (' ' + ' '.join(self._fmt_arg(a) for a in self.args)) if self.args else '') class Literal (Statement) : """ @@ -143,6 +177,9 @@ Parameters have a name, and optionally, a number of arguments, and are formatted as statements terminated with a semicolon. For convenience, params/decls that are None are ignored. + + The parameter will be formatted like this: + [ [ ... ] ] ";" """ def fmt_lines (self) : diff -r 2223ade4f259 -r e66102ab7048 main.py --- a/main.py Thu Apr 02 20:19:18 2009 +0300 +++ b/main.py Thu Apr 02 20:54:37 2009 +0300 @@ -51,7 +51,7 @@ options, (data_file, ) = parse_args(argv) # load the data - data_module = data.load_py(data_file) + data_module = data.load_py('pvl_hosts_data', data_file) # write out the config files write_dhcp(options, data_module) diff -r 2223ade4f259 -r e66102ab7048 test_dhcp.py --- a/test_dhcp.py Thu Apr 02 20:19:18 2009 +0300 +++ b/test_dhcp.py Thu Apr 02 20:54:37 2009 +0300 @@ -3,19 +3,42 @@ Test conf_dhcp """ -import dhcp_conf as dhcpc, conf, addr +import dhcp_conf as dhcpc, dhcp, addr import unittest -from cStringIO import StringIO -class TestConfDHCP (unittest.TestCase) : +class _TestConfObj (unittest.TestCase) : + def assert_obj (self, obj, lines) : + """ + Formats the given conf.Object and compares the output against the given lines + """ + + for obj_line, line in zip(obj.fmt_lines(), lines) : + self.assertEqual(obj_line, line) + +class TestDHCPConf (_TestConfObj) : def assert_stmt (self, stmt, line) : """ - Formats the given Statement, and compares the output against the given line + Formats the given Statement, and compares the output against the given line. + + Note that the dhcpc.Statement doesn't have a working fmt_lines implementation. """ self.assertEqual(stmt._fmt_data(), line) + def test_comment (self) : + self.assert_obj(dhcpc.Comment("foo bar"), [ "# foo bar" ]) + + def test_section (self) : + self.assert_obj(dhcpc.Section(comment="test"), [ "# test" ]) + + self.assert_obj(dhcpc.Section(params=[ + dhcpc.Parameter("param0"), None + ], comment="foo"), [ + "# foo", + "param0;", + ]) + def test_statement (self) : self.assert_stmt(dhcpc.Statement("stmt0"), "stmt0") self.assert_stmt(dhcpc.Statement("stmt1", [ "this", "that" ]), "stmt1 this, that") @@ -24,14 +47,7 @@ self.assert_stmt(dhcpc.Statement("stmt4", "bar"), "stmt4 bar") self.assert_stmt(dhcpc.Statement("stmt5", 1), "stmt5 1") self.assert_stmt(dhcpc.Statement("stmt6", 1, None, 2), "stmt6 1 2") - - def assert_obj (self, obj, lines) : - """ - Formats the given conf.Object and compares the output against the given lines - """ - - self.assertEqual(list(obj.fmt_lines()), lines) - + def test_literal (self) : self.assert_obj(dhcpc.Literal("///"), [ "///" ]) @@ -101,6 +117,55 @@ "option foo example.com;", ]) +class TestDHCP (_TestConfObj) : + def test_host (self) : + self.assert_obj(dhcp.Host("testhost", addr.MAC("12:34:56:78:90:ab"), addr.IP("1.2.3.4")), [ + "host testhost {", + "\thardware ethernet 12:34:56:78:90:ab;", + "\tfixed-address 1.2.3.4;", + "}" + ]) + + def test_subnet (self) : + self.assert_obj(dhcp.Subnet(addr.Network("1.2.3.0/24")), [ + "subnet 1.2.3.0 netmask 255.255.255.0 {", + "\toption routers 1.2.3.1;", + "}" + ]) + + self.assert_obj(dhcp.Subnet(addr.Network("1.2.3.0/24"), router_idx=10, range=(20, 30), unknown_clients='allow'), [ + "subnet 1.2.3.0 netmask 255.255.255.0 {", + "\toption routers 1.2.3.10;", + "\trange 1.2.3.20 1.2.3.30;", + "\tallow unknown-clients;", + "}" + ]) + + def test_config (self) : + self.assert_obj(dhcp.Config( + settings = { 'foo-setting': 'someval' }, + options = { 'bar-opt': ['one', 'two'] }, + shared_network = "FOO-NET", + subnets = [ + dhcp.Subnet(addr.Network("1.2.3.0/24")) + ], + hosts = [ + dhcp.Host("testhost", addr.MAC("12:34:56:78:90:ab"), addr.IP("1.2.3.4")) + ], + ), [ + "foo-setting someval;", + "option bar-opt one, two;", + "shared-network FOO-NET {", + "\tsubnet 1.2.3.0 netmask 255.255.255.0 {", + "\t\toption routers 1.2.3.1;", + "\t}", + "}", + "host testhost {", + "\thardware ethernet 12:34:56:78:90:ab;", + "\tfixed-address 1.2.3.4;", + "}" + ]) + if __name__ == '__main__' : unittest.main()