pvl/hosts/dhcp.py
changeset 739 5149c39f3dfc
parent 733 45bedeba92e5
--- a/pvl/hosts/dhcp.py	Mon Mar 09 23:31:13 2015 +0200
+++ b/pvl/hosts/dhcp.py	Tue Mar 10 00:11:43 2015 +0200
@@ -1,6 +1,93 @@
 import pvl.dhcp.config
 import pvl.hosts.host
 
+def parse_dhcp_boot(boot):
+    """
+        Parse the dhcp boot=... option
+
+        >>> print parse_dhcp_boot(None)
+        {}
+        >>> print parse_dhcp_boot({'filename': '/foo'})
+        {'filename': '/foo'}
+        >>> print parse_dhcp_boot({'filename': '/foo', 'next-server': 'bar'})
+        {'next-server': 'bar', 'filename': '/foo'}
+        >>> print parse_dhcp_boot('/foo')
+        {'filename': '/foo'}
+        >>> print parse_dhcp_boot('bar:/foo')
+        {'next-server': 'bar', 'filename': '/foo'}
+        >>> print parse_dhcp_boot('bar:')
+        {'next-server': 'bar'}
+        >>> print parse_dhcp_boot('foo')
+        Traceback (most recent call last):
+            ...
+        ValueError: invalid boot=foo
+    """
+    
+    # unpack dict, or str
+    if not boot:
+        filename = next_server = None
+        boot_str = None
+
+    elif isinstance(boot, dict):
+        filename = boot.pop('filename', None)
+        next_server = boot.pop('next-server', None)
+        boot_str = boot.pop(None, None)
+
+    else:
+        filename = next_server = None
+        boot_str = boot
+        boot = None
+        
+    if boot:
+        raise ValueError("Invalid boot.*: {instances}".format(instances=' '.join(boot)))
+    
+    # any boot= given overrides boot.* fields
+    if not boot_str:
+        pass
+
+    elif boot_str.startswith('/'):
+        filename = boot_str
+
+    elif boot_str.endswith(':'):
+        next_server = boot_str[:-1]
+
+    elif ':' in boot_str:
+        next_server, filename = boot_str.split(':', 1)
+
+    else :
+        raise ValueError("invalid boot={boot}".format(boot=boot_str))
+    
+    return next_server, filename
+
+@pvl.hosts.host.register_extension
+class HostDHCP(pvl.hosts.host.HostExtension):
+    EXTENSION = 'dhcp'
+    EXTENSION_FIELDS = (
+            'boot',
+    )
+
+    @classmethod
+    def build (cls,
+            boot        = None,
+            subclass    = None,
+    ):
+        next_server, filename = parse_dhcp_boot(boot)
+
+        return cls(
+                filename    = filename,
+                subclass    = subclass,
+                next_server = next_server,
+        )
+
+    def __init__(self,
+            filename    = None,
+            next_server = None,
+            subclass    = None,
+    ):
+        self.filename = filename
+        self.next_server = next_server
+        self.subclass = subclass
+
 def dhcp_host_subclass (host, subclass, ethernet):
     """
         Build a DHCP Item for declaring a subclass for a host.
@@ -16,7 +103,7 @@
 class HostDHCPError(pvl.hosts.host.HostError):
     pass
 
-def dhcp_host_options (host, ethernet, subclass=None):
+def dhcp_host_options (host, ethernet, dhcp=None):
     """
         Yield specific dhcp.conf host { ... } items.
     """
@@ -26,20 +113,17 @@
 
     if host.ip4:
         yield 'fixed-address', pvl.dhcp.config.Field(str(host.ip4))
-      
-    for bootopt in ('next-server', 'filename'):
-        if bootopt in host.boot:
-            yield bootopt, host.boot[bootopt]
+    
+    if dhcp:
+        if dhcp.next_server:
+            yield 'next-server', dhcp.next_server
 
-def dhcp_host (host,
-        subclass    = None,
-):
+        if dhcp.filename:
+            yield 'filename', dhcp.filename
+
+def dhcp_host (host):
     """
-        Yield pvl.dhcp.config.Block's
-
-        Takes dhcp:* extensions as keyword arguments
-
-            subclass: name      - generate a subclass name $ethernet for this host
+        Yield pvl.dhcp.config.Block's for given Host, with possible HostDHCP extensions.
     """
 
     if not host.ethernet:
@@ -50,6 +134,8 @@
         comment = u"Owner: {host.owner}".format(host=host)
     else:
         comment = None
+    
+    dhcp = host.extensions.get('dhcp')
 
     for index, ethernet in host.ethernet.iteritems() :
         if index:
@@ -57,12 +143,12 @@
         else:
             name = '{host.name}'.format(host=host)
 
-        items = list(dhcp_host_options(host, ethernet))
+        items = list(dhcp_host_options(host, ethernet, dhcp=dhcp))
 
         yield pvl.dhcp.config.Block(('host', name), items, comment=comment)
 
-        if subclass:
-            yield dhcp_host_subclass(host, subclass, ethernet)
+        if dhcp and dhcp.subclass:
+            yield dhcp_host_subclass(host, dhcp.subclass, ethernet)
     
 def dhcp_hosts (hosts):
     """
@@ -73,9 +159,7 @@
     blocks = { }
 
     for host in hosts:
-        extensions = host.extensions.get('dhcp', {})
-
-        for block in dhcp_host(host, **extensions):
+        for block in dhcp_host(host):
             if not block.key:
                 # TODO: check for unique Item-Blocks
                 pass