fix up data.load_py, and make conf.File be a ConfObject itself - implement this for dhcp_conf
authorTero Marttila <terom@fixme.fi>
Thu, 02 Apr 2009 20:54:37 +0300
changeset 2 e66102ab7048
parent 1 2223ade4f259
child 3 ff98fa9b84ce
fix up data.load_py, and make conf.File be a ConfObject itself - implement this for dhcp_conf
data.py
dhcp_conf.py
main.py
test_dhcp.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
-
--- 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:
+            "#" <comment>
+    """
+
+    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:
-                <name> [ <arg> [ ... ] ] ";"
-
             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:
+            <name> [ <arg> [ ... ] ] ";"
     """
     
     def fmt_lines (self) :
--- 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)
--- 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()