pvl/hosts.py
changeset 331 9dda6a0e9826
parent 308 08176bed21e3
child 333 7d2601368142
equal deleted inserted replaced
330:3954e7b5ade1 331:9dda6a0e9826
     8 import configobj
     8 import configobj
     9 import ipaddr
     9 import ipaddr
    10 import optparse
    10 import optparse
    11 import os.path
    11 import os.path
    12 
    12 
       
    13 import logging; log = logging.getLogger('pvl.hosts')
       
    14 
    13 def optparser (parser) :
    15 def optparser (parser) :
    14     hosts = optparse.OptionGroup(parser, "Hosts input")
    16     hosts = optparse.OptionGroup(parser, "Hosts input")
    15     hosts.add_option('--hosts-charset',         metavar='CHARSET',  default='utf-8', 
    17     hosts.add_option('--hosts-charset',         metavar='CHARSET',  default='utf-8', 
    16             help="Encoding used for host files")
    18             help="Encoding used for host files")
    17 
    19 
    24     # the label used for alias4/6 hosts
    26     # the label used for alias4/6 hosts
    25     ALIAS4_FMT = '{host}-ipv4'
    27     ALIAS4_FMT = '{host}-ipv4'
    26     ALIAS6_FMT = '{host}-ipv6'
    28     ALIAS6_FMT = '{host}-ipv6'
    27 
    29 
    28     @classmethod
    30     @classmethod
    29     def expand (cls, options, host, range, ip, **opts) :
    31     def expand (cls, options, range, host, domain, ip, **opts) :
    30         host = pvl.dns.zone.parse_generate_field(host)
    32         host = pvl.dns.zone.parse_generate_field(host)
    31         ip = pvl.dns.zone.parse_generate_field(ip)
    33         ip = pvl.dns.zone.parse_generate_field(ip)
    32 
    34 
    33         for i in range :
    35         for i in range :
    34             yield cls.build(options, host(i),
    36             yield cls.build(options, host(i), domain,
    35                     ip  = ip(i),
    37                     ip  = ip(i),
    36                     **opts
    38                     **opts
    37             )
    39             )
    38 
    40 
    39     @classmethod
    41     @classmethod
    40     def config (cls, options, host, ip=None, **extra) :
    42     def config (cls, options, host, section=None, domain=None, ip=None, **extra) :
    41         """
    43         """
    42             Yield Hosts from a config section's scalars.
    44             Yield Hosts from a config section's scalars.
    43         """
    45 
    44 
    46                 options     - pvl.args Options
       
    47                 host        - the name of the section (or file) containing this host item.
       
    48                 section     - the parent section containing this host item, or None
       
    49                               used for domain
       
    50         """
       
    51 
       
    52         if domain :
       
    53             log.debug("%s: explicit domain: %s", host, domain)
       
    54         elif options.hosts_domain :
       
    55             log.debug("%s: default domain to --hots-domain: %s", host, options.hosts_domain)
       
    56             domain = options.hosts_domain
       
    57         elif section :
       
    58             log.debug("%s: default domain to section: %s", host, section)
       
    59             domain = section
       
    60         elif '.' in host :
       
    61             log.debug("%s: using as fqdn without domain", host)
       
    62             domain = None
       
    63         else :
       
    64             raise ValueError("%s: no domain given" % (host, ))
       
    65  
    45         if '{' in host :
    66         if '{' in host :
    46             pre, host = host.split('{', 1)
    67             pre, host = host.split('{', 1)
    47             range, post = host.rsplit('}', 1)
    68             range, post = host.rsplit('}', 1)
    48             
    69             
    49             range = pvl.dns.zone.parse_generate_range(range)
    70             range = pvl.dns.zone.parse_generate_range(range)
    50             host = pre + "$" + post
    71             host = pre + "$" + post
    51 
    72 
    52             for host in cls.expand(options, host, range, ip, **extra) :
    73             for host in cls.expand(options, range, host, domain, ip, **extra) :
    53                 yield host
    74                 yield host
    54         else :
    75         else :
    55             yield cls.build(options, host, ip=ip, **extra)
    76             yield cls.build(options, host, domain, ip=ip, **extra)
    56     
    77     
    57     @classmethod
    78     @classmethod
    58     def build (cls, options, host, domain=None, ip=None, ip6=None, owner=None, boot=None, alias=None, alias4=None, alias6=None, **extra) :
    79     def build (cls, options, host, domain,
       
    80             ip=None, ip6=None, owner=None, boot=None, alias=None, alias4=None, alias6=None, forward=None, reverse=None,
       
    81             **extra) :
    59         """
    82         """
    60             Return a Host from a config section's scalars.
    83             Return a Host from a config section's scalars.
       
    84 
    61         """
    85         """
    62 
    86 
    63         if alias :
    87         if alias :
    64             alias = alias.split()
    88             alias = alias.split()
    65         else :
    89         else :
    90                     for eth in value.split() :
   114                     for eth in value.split() :
    91                         ethernet[len(ethernet)] = eth
   115                         ethernet[len(ethernet)] = eth
    92             else :
   116             else :
    93                 raise ValueError("%s: Unknown host field: %s=%s" % (host, field, value))
   117                 raise ValueError("%s: Unknown host field: %s=%s" % (host, field, value))
    94         
   118         
    95         if domain is None :
   119        
    96             domain = options.hosts_domain
   120         if forward is None :
       
   121             # normal zone
       
   122             pass
       
   123         elif forward :
       
   124             # alias to external zone
       
   125             pass
       
   126         else :
       
   127             # omit
       
   128             forward = False
    97         
   129         
       
   130         if reverse is None :
       
   131             # normal zone
       
   132             pass
       
   133         elif reverse :
       
   134             # alias to external zone
       
   135             pass
       
   136         else :
       
   137             # omit
       
   138             reverse = False
       
   139        
    98         return cls(host,
   140         return cls(host,
    99                 domain      = domain,
   141                 domain      = domain,
   100                 ip          = ipaddr.IPv4Address(ip) if ip else None,
   142                 ip          = ipaddr.IPv4Address(ip) if ip else None,
   101                 ip6         = ipaddr.IPv6Address(ip6) if ip6 else None,
   143                 ip6         = ipaddr.IPv6Address(ip6) if ip6 else None,
   102                 ethernet    = ethernet,
   144                 ethernet    = ethernet,
   103                 alias       = alias,
   145                 alias       = alias,
   104                 alias4      = alias4,
   146                 alias4      = alias4,
   105                 alias6      = alias6,
   147                 alias6      = alias6,
   106                 owner       = owner,
   148                 owner       = owner,
   107                 boot        = boot,
   149                 boot        = boot,
       
   150                 forward     = forward,
       
   151                 reverse     = reverse,
   108         )
   152         )
   109 
   153 
   110     def __init__ (self, host, domain=None, ip=None, ip6=None, ethernet={ }, alias=(), owner=None, boot=None, alias4=None, alias6=None) :
   154     def __init__ (self, host,
       
   155             domain=None,
       
   156             ip=None, ip6=None,
       
   157             ethernet={ },
       
   158             alias=(),
       
   159             owner=None,
       
   160             boot=None,
       
   161             alias4=None, alias6=None,
       
   162             forward=None, reverse=None,
       
   163     ) :
   111         """
   164         """
   112             host        - str
   165             host        - str
   113             domain      - str
   166             domain      - str
   114             ip          - ipaddr.IPv4Address
   167             ip          - ipaddr.IPv4Address
   115             ip6         - ipaddr.IPv6Address
   168             ip6         - ipaddr.IPv6Address
   116             ethernet    - { index: ethernet }
   169             ethernet    - { index: ethernet }
   117             alias       - list
   170             alias       - list
   118             owner       - str: LDAP uid
   171             owner       - str: LDAP uid
   119             alias4      - list (CNAME -> A)
   172             alias4      - list (CNAME -> A)
   120             alias6      - list (CNAME -> AAAA)
   173             alias6      - list (CNAME -> AAAA)
   121         """
   174             forward     - generate forward records, or CNAME into given zone
       
   175             reverse     - generate reverse records, or CNAME into given zone
       
   176         """
       
   177 
   122         self.host = host
   178         self.host = host
   123         self.domain = domain
   179         self.domain = domain
   124         self.ip = ip
   180         self.ip = ip
   125         self.ip6 = ip6
   181         self.ip6 = ip6
   126         self.ethernet = ethernet
   182         self.ethernet = ethernet
   127         self.alias = alias
   183         self.alias = alias
   128         self.alias4 = alias4
   184         self.alias4 = alias4
   129         self.alias6 = alias6
   185         self.alias6 = alias6
   130         self.owner = owner
   186         self.owner = owner
   131         self.boot = boot
   187         self.boot = boot
       
   188         self.forward = forward
       
   189         self.reverse = reverse
   132 
   190 
   133     def fqdn (self) :
   191     def fqdn (self) :
   134         if '.' in self.host :
   192         if '.' in self.host :
   135             return self.host + '.'
   193             return self.host + '.'
   136         elif self.domain :
   194         elif self.domain :
   139             raise ValueError("%s: have no fqdn/domain" % (self, ))
   197             raise ValueError("%s: have no fqdn/domain" % (self, ))
   140 
   198 
   141     def __str__ (self) :
   199     def __str__ (self) :
   142         return str(self.host)
   200         return str(self.host)
   143 
   201 
   144 def apply_hosts_config (options, config, name, defaults={}) :
   202 def apply_hosts_config (options, config, name, defaults={}, parent=None) :
   145     """
   203     """
   146         Load hosts from a ConfigObj section.
   204         Load hosts from a ConfigObj section.
   147     """
   205     """
   148 
   206 
   149     scalars = dict((scalar, config[scalar]) for scalar in config.scalars)
   207     scalars = dict((scalar, config[scalar]) for scalar in config.scalars)
   150 
   208 
   151     if config.sections :
   209     if config.sections :
   152         # recurse; this is a domain meta-section
   210         # recurse; this is a domain meta-section
   153         params = dict(defaults, domain=name)
   211         params = dict(defaults)
   154         params.update(**scalars) # override
   212         params.update(**scalars) # override
   155 
   213 
   156         for section in config.sections :
   214         for section in config.sections :
   157             for host in apply_hosts_config(options, config[section], section, params) :
   215             for host in apply_hosts_config(options, config[section], section, params, name) :
   158                 yield host
   216                 yield host
   159 
   217 
   160     elif name :
   218     elif name :
   161         params = dict(defaults, **scalars)
   219         params = dict(defaults, **scalars)
   162 
   220 
   163         # this is a host section
   221         # this is a host section
   164         for host in Host.config(options, name, **params) :
   222         for host in Host.config(options, name, parent, **params) :
   165             yield host
   223             yield host
   166 
   224 
   167     else :
   225     else :
   168         raise ValueError("No sections in config")
   226         raise ValueError("No sections in config")
   169 
   227