conf_dhcp.py
changeset 1 2223ade4f259
parent 0 257003279747
child 2 e66102ab7048
equal deleted inserted replaced
0:257003279747 1:2223ade4f259
     1 """
       
     2     Configuration file output for the ISC DHCP server
       
     3 """
       
     4 
       
     5 import conf
       
     6 
       
     7 import itertools
       
     8 
       
     9 class ConfDHCP (conf.File) :
       
    10     def __init__ (self, name="dhcpd.conf", path="/etc/dhcp3/dhcpd.conf") :
       
    11         """
       
    12             Initialize the dhcpd config file, but don't open it yet
       
    13 
       
    14             @see conf.ConfFile.__init__
       
    15         """
       
    16         
       
    17         super(ConfDHCP, self).__init__(name, path)
       
    18 
       
    19 class Statement (conf.Object) :
       
    20     """
       
    21       A statement is a single line in the config file
       
    22     """
       
    23 
       
    24     def __init__ (self, name, *args) :
       
    25         """
       
    26             The statement will be formatted like this:
       
    27                 <name> [ <arg> [ ... ] ] ";"
       
    28         """
       
    29 
       
    30         self.name = name
       
    31         self.args = args
       
    32     
       
    33     def _fmt_arg (self, arg) :
       
    34         """
       
    35             Formats a arg for use in output, the following types are supported:
       
    36 
       
    37                 list/tuple/iter:    results in a comma-and-space separated list of formatted values
       
    38                 unicode:            results in an encoded str
       
    39                 str:                results in the string itself, quoted if needed
       
    40                 other:              attempt to convert to a str, and then format that
       
    41         """
       
    42         
       
    43         # format lists specially
       
    44         # XXX: iterators?
       
    45         if isinstance(arg, (list, tuple)) :
       
    46             # recurse as a comma-and-space separated list
       
    47             return ', '.join(self._fmt_arg(a) for a in arg)
       
    48 
       
    49         elif isinstance(arg, Literal) :
       
    50             # use what it specifies
       
    51             return arg.fmt_arg()
       
    52 
       
    53         elif isinstance(arg, unicode) :
       
    54             # recurse with the str version
       
    55             # XXX: what encoding to use?
       
    56             return self._fmt_arg(arg.encode('utf8'))
       
    57 
       
    58         elif isinstance(arg, str) :
       
    59             # XXX: quoting
       
    60             return arg
       
    61         
       
    62         else :
       
    63             # try and use it as a string
       
    64             return self._fmt_arg(str(arg))
       
    65     
       
    66     def _fmt_data (self) :
       
    67         """
       
    68             Formats the statement name/params as a single line
       
    69         """
       
    70 
       
    71         return "%s%s" % (self.name, (' ' + ' '.join(self._fmt_arg(a) for a in self.args)) if self.args else '')
       
    72 
       
    73 class Literal (Statement) :
       
    74     """
       
    75         A literal is something that goes into the config file as-is, with no formatting or escaping applied.
       
    76     """
       
    77 
       
    78     def __init__ (self, literal) :
       
    79         self.literal = literal
       
    80     
       
    81     def fmt_arg (self) :
       
    82         return self.literal
       
    83 
       
    84     def fmt_lines (self) :
       
    85         yield self.literal
       
    86 
       
    87 class Parameter (Statement) :
       
    88     """
       
    89         A parameter is a single statement that configures the behaviour of something.
       
    90 
       
    91         Parameters have a name, and optionally, a number of arguments, and are formatted as statements terminated with
       
    92         a semicolon.
       
    93     """
       
    94     
       
    95     def fmt_lines (self) :
       
    96         """
       
    97             Yields a single ;-terminated line
       
    98         """
       
    99 
       
   100         yield "%s;" % self._fmt_data()
       
   101 
       
   102 class Declaration (Statement) :
       
   103     """
       
   104         A declaration begins like a statement (with name and args), but then contains a block of any number of
       
   105         parameters followed by any number of nested declarations.
       
   106 
       
   107         <name> [ <args> [ ... ] ] {
       
   108             [ <parameters> ]
       
   109             [ <declarations> ]
       
   110         }
       
   111         
       
   112     """
       
   113 
       
   114     def __init__ (self, name, args=[], params=[], decls=[]) :
       
   115         """
       
   116             The name/args will be formatted as in Statement, but params should be an iterable of Parameters, and decls
       
   117             an iterable of Declarations.
       
   118         """
       
   119         
       
   120         # init the statement bit
       
   121         Statement.__init__(self, name, *args)
       
   122 
       
   123         # store the iterables
       
   124         self.params = params
       
   125         self.decls = decls
       
   126 
       
   127     def fmt_lines (self) :
       
   128         """
       
   129             Yields a header line, a series of indented body lines, and the footer line
       
   130         """
       
   131         
       
   132         # the header to open the block
       
   133         yield "%s {" % self._fmt_data()
       
   134         
       
   135         # then output each content line
       
   136         for stmt in itertools.chain(self.params, self.decls) :
       
   137             # ..indented
       
   138             for line in stmt.fmt_lines() :
       
   139                 yield "\t%s" % line
       
   140         
       
   141         # and then close the block
       
   142         yield "}"
       
   143 
       
   144 class SharedNetwork (Declaration) :
       
   145     """
       
   146         A shared-network declaration is used to define a set of subnets that share the same physical network,
       
   147         optionally with some shared params.
       
   148 
       
   149         shared-network <name> {
       
   150             [ parameters ]
       
   151             [ declarations ]
       
   152         }
       
   153     """
       
   154 
       
   155     def __init__ (self, name, params=[], decls=[]) :
       
   156         """
       
   157             @param name the name of the shared-subnet
       
   158             @param params optional parameters
       
   159             @param decls the iterable of subnets or other declarations in the shared network
       
   160         """
       
   161 
       
   162         super(SharedNetwork, self).__init__("shared-network", [name], params, decls)
       
   163 
       
   164 class Subnet (Declaration) :
       
   165     """
       
   166         A subnet is used to provide the information about a subnet required to identify whether or not an IP address is
       
   167         on that subnet, and may also be used to specify parameters/declarations for that subnet.
       
   168         
       
   169         subnet <subnet-number> netmask <netmask> {
       
   170             [ parameters ]
       
   171             [ declarations ]
       
   172         }
       
   173     """
       
   174 
       
   175     def __init__ (self, network, params=[], decls=[]) :
       
   176         """
       
   177             @param network the addr.Network for the subnet
       
   178             @param params optional parameters
       
   179             @param decls optional decls, e.g. subnets
       
   180         """
       
   181 
       
   182         super(Subnet, self).__init__("subnet", [network.net(), "netmask", network.netmask()], params, decls)
       
   183 
       
   184 class Group (Declaration) :
       
   185     """
       
   186         A group is simply used to apply a set of parameters to a set of declarations.
       
   187 
       
   188         group {
       
   189             [ parameters ]
       
   190             [ declarations ]
       
   191         }
       
   192     """
       
   193 
       
   194     def __init__ (self, params=[], decls=[]) :
       
   195         super(Group, self).__init__("group", [], params, decls)
       
   196 
       
   197 
       
   198 class Host (Declaration) :
       
   199     """
       
   200         A host is used to match a request against specific host, and then apply settings for that host.
       
   201 
       
   202         The "hostname" is the DHCP name to identify the host. 
       
   203 
       
   204         If no dhcp-client-identifier option is specified in the parameters, then the host is matched using the
       
   205         "hardware" parameter.
       
   206 
       
   207         host <hostname> {
       
   208             [ parameters ]
       
   209             [ declarations ]
       
   210         }
       
   211     """
       
   212 
       
   213     def __init__ (self, hostname, params=[], decls=[]) :
       
   214         super(Host, self).__init__("host", [hostname], params, decls)
       
   215 
       
   216 class Option (Parameter) :
       
   217     """
       
   218         A generic 'option' parameter for a dhcpd.conf file
       
   219     """
       
   220 
       
   221     def __init__ (self, name, *args) :
       
   222         """
       
   223             Formatted as a Satement with a name of "option <name>".
       
   224         """
       
   225 
       
   226         super(Option, self).__init__("option %s" % name, *args)
       
   227