pvl/dns/zone.py
author Tero Marttila <terom@paivola.fi>
Mon, 16 Dec 2013 18:36:09 +0200
changeset 267 8c0c1b6e6aff
parent 257 a6964f9bda8b
child 270 bafcda3a3c0d
permissions -rw-r--r--
pvl.dns.zone: ZoneRecord.A/CNAME
247
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     1
#!/usr/bin/env python
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     2
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     3
"""
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     4
    Process zonefiles.
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     5
"""
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     6
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     7
import codecs
253
8f59ee92583d pvl.dns.zone: tweak datetime import
Tero Marttila <terom@paivola.fi>
parents: 252
diff changeset
     8
import datetime
247
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     9
import logging
254
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
    10
import os.path
247
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    11
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    12
log = logging.getLogger('pvl.dns.zone')
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    13
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    14
class ZoneError (Exception) :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    15
    pass
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    16
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    17
class ZoneLineError (ZoneError) :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    18
    """
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    19
        ZoneLine-related error
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    20
    """
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    21
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    22
    def __init__ (self, line, msg, *args, **kwargs) :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    23
        super(ZoneLineError, self).__init__("%s: %s" % (line, msg.format(*args, **kwargs)))
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    24
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    25
class ZoneLine (object) :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    26
    """
250
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    27
        A line parsed from a zonefile.
247
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    28
    """
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    29
250
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    30
    @classmethod
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    31
    def load (cls, file, filename=None, line_timestamp_prefix=None) :
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    32
        """
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    33
            Yield ZoneLines lexed from a file.
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    34
        """
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    35
        
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    36
        if not filename :
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    37
            filename = file.name
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    38
        
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    39
        multiline_start = None
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    40
        multiline_parts = None
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    41
        
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    42
        for lineno, raw_line in enumerate(file) :
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    43
            # possible mtime prefix for line
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    44
            timestamp = None
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    45
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    46
            if line_timestamp_prefix :
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    47
                if ': ' not in raw_line :
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    48
                    raise ZoneError("%s:%d: Missing timestamp prefix: %s" % (filename, lineno, raw_line))
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    49
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    50
                # split prefix
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    51
                prefix, raw_line = raw_line.split(': ', 1)
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    52
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    53
                # parse it out
253
8f59ee92583d pvl.dns.zone: tweak datetime import
Tero Marttila <terom@paivola.fi>
parents: 252
diff changeset
    54
                timestamp = datetime.datetime.strptime(prefix, cls.PARSE_DATETIME_FORMAT)
250
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    55
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    56
                log.debug("%s:%d: ts=%r", filename, lineno, ts)
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    57
            
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    58
            log.debug("%s:%d: %s", filename, lineno, raw_line)
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    59
            
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    60
            # capture indent from raw line
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    61
            indent = raw_line.startswith(' ') or raw_line.startswith('\t')
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    62
            line = raw_line.strip()
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    63
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    64
            # parse comment
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    65
            if ';' in line:
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    66
                line, comment = line.split(';', 1)
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    67
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    68
                line = line.strip()
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    69
                comment = comment.strip()
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    70
            else :
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    71
                comment = None
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    72
           
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    73
            log.debug("%s:%d: indent=%r, line=%r, comment=%r", filename, lineno, indent, line, comment)
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    74
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    75
            # split (quoted) fields
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    76
            if '"' in line :
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    77
                pre, data, post = line.split('"', 2)
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    78
                parts = pre.split() + [data] + post.split()
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    79
               
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    80
            else :
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    81
                parts = line.split()
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    82
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    83
            # handle multi-line statements...
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    84
            if '(' in parts :
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    85
                assert not multiline_start
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    86
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    87
                log.warn("%s:%d: Start of multi-line statement: %s", filename, lineno, line)
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    88
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    89
                multiline_start = (lineno, timestamp, indent, comment)
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    90
                multiline_line = raw_line
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    91
                multiline_parts = []
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    92
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    93
            if multiline_start:
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    94
                log.warn("%s:%d: Multi-line statement: %s", filename, lineno, line)
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    95
                
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    96
                # XXX: some better way to do this
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    97
                multiline_parts.extend([part for part in parts if part not in set('()')])
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    98
                multiline_line += raw_line
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
    99
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   100
            if ')' in parts :
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   101
                assert multiline_start
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   102
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   103
                log.warn("%s:%d: End of multi-line statement: %s", filename, lineno, line)
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   104
                
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   105
                lineno, timestamp, indent, comment = multiline_start
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   106
                raw_line = multiline_line
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   107
                parts = multiline_parts
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   108
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   109
                multiline_start = multiline_line = multiline_parts = None
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   110
        
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   111
            # parse
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   112
            if multiline_start:
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   113
                pass
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   114
            else:
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   115
                yield ZoneLine(filename, lineno, raw_line, indent, parts, comment, timestamp=timestamp)
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   116
247
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   117
    file = None
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   118
    lineno = None
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   119
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   120
    # data
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   121
    indent = None # was the line indented?
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   122
    parts = None # split line fields
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   123
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   124
    # optional
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   125
    timestamp = None
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   126
    comment = None
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   127
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   128
    PARSE_DATETIME_FORMAT = '%Y-%m-%d'
250
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   129
    
248
cce9cf4933ca pvl.dns.zone: more multi-line support in the parser..
Tero Marttila <terom@paivola.fi>
parents: 247
diff changeset
   130
    def __init__ (self, file, lineno, line, indent, parts, comment=None, timestamp=None) :
cce9cf4933ca pvl.dns.zone: more multi-line support in the parser..
Tero Marttila <terom@paivola.fi>
parents: 247
diff changeset
   131
        # source
247
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   132
        self.file = file
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   133
        self.lineno = lineno
248
cce9cf4933ca pvl.dns.zone: more multi-line support in the parser..
Tero Marttila <terom@paivola.fi>
parents: 247
diff changeset
   134
        self.line = line
cce9cf4933ca pvl.dns.zone: more multi-line support in the parser..
Tero Marttila <terom@paivola.fi>
parents: 247
diff changeset
   135
        
cce9cf4933ca pvl.dns.zone: more multi-line support in the parser..
Tero Marttila <terom@paivola.fi>
parents: 247
diff changeset
   136
        # parse data
247
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   137
        self.indent = indent
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   138
        self.parts = parts
248
cce9cf4933ca pvl.dns.zone: more multi-line support in the parser..
Tero Marttila <terom@paivola.fi>
parents: 247
diff changeset
   139
        
cce9cf4933ca pvl.dns.zone: more multi-line support in the parser..
Tero Marttila <terom@paivola.fi>
parents: 247
diff changeset
   140
        # metadata
247
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   141
        self.timestamp = timestamp
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   142
        self.comment = comment
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   143
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   144
    def __str__ (self) :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   145
        return "{file}:{lineno}".format(file=self.file, lineno=self.lineno)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   146
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   147
class ZoneRecord (object) :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   148
    """
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   149
        A record from a zonefile.
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   150
    """
250
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   151
    
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   152
    # context
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   153
    line = None # the underlying line
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   154
    origin = None # possible $ORIGIN context
247
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   155
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   156
    # record fields
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   157
    name = None
250
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   158
    ttl = None  # optional
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   159
    cls = None  # optional
247
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   160
    type = None
250
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   161
    data = None # list of data fields
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   162
    
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   163
    @classmethod
254
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   164
    def load (cls, file, ttl=None, origin=None, **opts) :
250
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   165
        """
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   166
            Parse ZoneRecord items from the given zonefile, ignoring non-record lines.
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   167
        """
247
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   168
254
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   169
        for line in ZoneLine.load(file, **opts) :
250
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   170
            if not line.parts :
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   171
                log.debug("%s: skip empty line", line)
247
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   172
250
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   173
            elif line.line.startswith('$') :
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   174
                # control record
254
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   175
                args = list(line.parts)
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   176
                directive = args.pop(0)[1:]
250
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   177
254
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   178
                if directive == 'ORIGIN' :
250
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   179
                    # update
254
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   180
                    origin, = args
250
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   181
                    
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   182
                    log.info("%s: origin: %s", line, origin)
254
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   183
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   184
                if directive == 'TTL' :
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   185
                    ttl, = args
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   186
                    
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   187
                    log.info("%s: ttl: %s", line, ttl)
250
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   188
                
254
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   189
                elif directive == 'GENERATE' :
250
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   190
                    # process...
254
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   191
                    log.info("%s: generate: %s", line, args)
250
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   192
254
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   193
                    for record in process_generate(line, origin, args) :
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   194
                        yield record
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   195
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   196
                elif directive == 'INCLUDE' :
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   197
                    include, = args
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   198
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   199
                    # XXX: this is probably not what we want...
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   200
                    path = os.path.join(os.path.dirname(file.name), include)
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   201
                    
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   202
                    log.info("%s: include: %s: %s", line, include, path)
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   203
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   204
                    for record in cls.load(open(path)) :
250
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   205
                        yield record
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   206
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   207
                else :
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   208
                    log.warning("%s: skip control record: %s", line, line.line)
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   209
                
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   210
            else :
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   211
                # normal record?
257
a6964f9bda8b pvl.dns.zone: pass comment to ZoneRecord
Tero Marttila <terom@paivola.fi>
parents: 254
diff changeset
   212
                record = ZoneRecord.parse(line, origin=origin, ttl=ttl,
a6964f9bda8b pvl.dns.zone: pass comment to ZoneRecord
Tero Marttila <terom@paivola.fi>
parents: 254
diff changeset
   213
                        comment = line.comment
a6964f9bda8b pvl.dns.zone: pass comment to ZoneRecord
Tero Marttila <terom@paivola.fi>
parents: 254
diff changeset
   214
                )
250
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   215
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   216
                if record :
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   217
                    yield record
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   218
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   219
                else :
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   220
                    # unknown
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   221
                    log.warning("%s: skip unknown line: %s", line, line.line)
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   222
     
247
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   223
    @classmethod
254
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   224
    def parse (cls, line, parts=None, ttl=None, **opts) :
247
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   225
        """
250
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   226
            Build a ZoneRecord from a ZoneLine.
247
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   227
        """
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   228
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   229
        if parts is None :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   230
            parts = list(line.parts)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   231
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   232
        if not parts :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   233
            # skip
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   234
            return
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   235
        
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   236
        # XXX: indented lines keep name from previous record
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   237
        if line.indent :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   238
            name = None
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   239
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   240
        else :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   241
            name = parts.pop(0)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   242
        
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   243
        if len(parts) < 2 :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   244
            raise ZoneLineError(line, "Too few parts to parse: {0!r}", line.data)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   245
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   246
        # parse ttl/cls/type
254
358b6e91659d ZoneRecord.parse: support $TTL, and very crudde $INCLUDE
Tero Marttila <terom@paivola.fi>
parents: 253
diff changeset
   247
        _cls = None
247
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   248
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   249
        if parts and parts[0][0].isdigit() :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   250
            ttl = parts.pop(0)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   251
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   252
        if parts and parts[0].upper() in ('IN', 'CH') :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   253
            _cls = parts.pop(0)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   254
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   255
        # always have type
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   256
        type = parts.pop(0)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   257
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   258
        # remaining parts are data
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   259
        data = parts
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   260
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   261
        log.debug("  ttl=%r, cls=%r, type=%r, data=%r", ttl, _cls, type, data)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   262
252
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   263
        return cls.build(line, name, ttl, _cls, type, data, **opts)
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   264
    
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   265
    @classmethod
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   266
    def build (_cls, line, name, ttl, cls, type, data, **opts) :
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   267
        return _cls(name, type, data,
247
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   268
            ttl     = ttl,
252
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   269
            cls     = cls,
247
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   270
            line    = line,
252
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   271
            **opts
247
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   272
        )
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   273
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   274
    @classmethod
267
8c0c1b6e6aff pvl.dns.zone: ZoneRecord.A/CNAME
Tero Marttila <terom@paivola.fi>
parents: 257
diff changeset
   275
    def A (cls, name, ip, **opts) :
8c0c1b6e6aff pvl.dns.zone: ZoneRecord.A/CNAME
Tero Marttila <terom@paivola.fi>
parents: 257
diff changeset
   276
        return cls(name, 'A', [ip], **opts)
8c0c1b6e6aff pvl.dns.zone: ZoneRecord.A/CNAME
Tero Marttila <terom@paivola.fi>
parents: 257
diff changeset
   277
8c0c1b6e6aff pvl.dns.zone: ZoneRecord.A/CNAME
Tero Marttila <terom@paivola.fi>
parents: 257
diff changeset
   278
    @classmethod
8c0c1b6e6aff pvl.dns.zone: ZoneRecord.A/CNAME
Tero Marttila <terom@paivola.fi>
parents: 257
diff changeset
   279
    def CNAME (cls, name, host, **opts) :
8c0c1b6e6aff pvl.dns.zone: ZoneRecord.A/CNAME
Tero Marttila <terom@paivola.fi>
parents: 257
diff changeset
   280
        return cls(name, 'CNAME', [host], **opts)
8c0c1b6e6aff pvl.dns.zone: ZoneRecord.A/CNAME
Tero Marttila <terom@paivola.fi>
parents: 257
diff changeset
   281
8c0c1b6e6aff pvl.dns.zone: ZoneRecord.A/CNAME
Tero Marttila <terom@paivola.fi>
parents: 257
diff changeset
   282
    @classmethod
247
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   283
    def TXT (cls, name, text, **opts) :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   284
        return cls(name, 'TXT',
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   285
            [u'"{0}"'.format(text.replace('"', '\\"'))], 
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   286
            **opts
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   287
        )
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   288
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   289
    @classmethod
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   290
    def PTR (cls, name, ptr, **opts) :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   291
        return cls(name, 'PTR', [ptr], **opts)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   292
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   293
    @classmethod
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   294
    def MX (cls, name, priority, mx, **opts) :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   295
        return cls(name, 'MX', [priority, mx], **opts)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   296
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   297
    def __init__ (self, name, type, data, origin=None, ttl=None, cls=None, line=None, comment=None) :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   298
        self.name = name
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   299
        self.type = type
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   300
        self.data = data
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   301
        
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   302
        self.ttl = ttl
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   303
        self.cls = cls
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   304
        
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   305
        self.origin = origin
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   306
        self.line = line
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   307
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   308
        self.comment = comment
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   309
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   310
    def __unicode__ (self) :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   311
        """
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   312
            Construct a zonefile-format line..."
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   313
        """
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   314
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   315
        if self.comment :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   316
            comment = '\t; ' + self._comment
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   317
        else :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   318
            comment = ''
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   319
            
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   320
        return u"{name:25} {ttl:4} {cls:2} {type:5} {data}{comment}".format(
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   321
                name    = self.name or '',
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   322
                ttl     = self.ttl or '',
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   323
                cls     = self.cls or '',
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   324
                type    = self.type,
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   325
                data    = ' '.join(unicode(data) for data in self.data),
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   326
                comment = comment,
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   327
        )
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   328
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   329
    def __repr__ (self) :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   330
        return '%s(%s)' % (self.__class__.__name__, ', '.join(repr(arg) for arg in (
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   331
            self.name, self.type, self.data
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   332
        )))
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   333
252
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   334
class SOA (ZoneRecord) :
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   335
    @classmethod
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   336
    def build (_cls, line, name, ttl, cls, type, data, **opts) :
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   337
        assert name == '@'
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   338
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   339
        return _cls(*data,
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   340
            ttl     = ttl,
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   341
            cls     = cls,
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   342
            line    = line,
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   343
            **opts
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   344
        )
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   345
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   346
    def __init__ (self, master, contact, serial, refresh, retry, expire, nxttl, **opts) :
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   347
        super(SOA, self).__init__('@', 'SOA',
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   348
            [master, contact, serial, refresh, retry, expire, nxttl],
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   349
            **opts
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   350
        )
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   351
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   352
        self.master = master
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   353
        self.contact = contact
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   354
        self.serial = serial
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   355
        self.refresh = refresh
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   356
        self.retry = retry
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   357
        self.expire = expire
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   358
        self.nxttl = nxttl
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   359
247
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   360
class OffsetValue (object) :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   361
    """
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   362
        Magic for $GENERATE offsets.
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   363
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   364
        >>> OffsetValue(0)[1]
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   365
        1
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   366
        >>> OffsetValue(10)[5]
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   367
        15
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   368
    """
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   369
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   370
    def __init__ (self, base) :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   371
        self.base = base
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   372
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   373
    def __getitem__ (self, offset) :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   374
        return self.base + offset
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   375
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   376
def parse_generate_field (line, field) :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   377
    """
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   378
        Parse a $GENERATE lhs/rhs field:
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   379
            $
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   380
            ${<offset>[,<width>[,<base>]]}
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   381
            \$
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   382
            $$
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   383
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   384
        Returns a wrapper that builds the field-value when called with the index.
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   385
        
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   386
        >>> parse_generate_field(None, "foo")(1)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   387
        'foo'
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   388
        >>> parse_generate_field(None, "foo-$")(1)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   389
        'foo-1'
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   390
        >>> parse_generate_field(None, "foo-$$")(1)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   391
        'foo-$'
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   392
        >>> parse_generate_field(None, "\$")(1)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   393
        '$'
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   394
        >>> parse_generate_field(None, "10.0.0.${100}")(1)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   395
        '10.0.0.101'
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   396
        >>> parse_generate_field(None, "foo-${0,2,d}")(1)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   397
        'foo-01'
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   398
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   399
    """
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   400
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   401
    input = field
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   402
    expr = []
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   403
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   404
    while '$' in field :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   405
        # defaults
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   406
        offset = 0
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   407
        width = 0
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   408
        base = 'd'
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   409
        escape = False
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   410
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   411
        # different forms
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   412
        if '${' in field :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   413
            pre, body = field.split('${', 1)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   414
            body, post = body.split('}', 1)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   415
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   416
            # parse body
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   417
            parts = body.split(',')
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   418
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   419
            # offset
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   420
            offset = int(parts.pop(0))
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   421
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   422
            # width
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   423
            if parts :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   424
                width = int(parts.pop(0))
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   425
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   426
            # base
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   427
            if parts :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   428
                base = parts.pop(0)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   429
            
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   430
            if parts:
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   431
                # fail
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   432
                raise ZoneLineError(line, "extra data in ${...} body: {0!r}", parts)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   433
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   434
        elif '$$' in field :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   435
            pre, post = field.split('$$', 1)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   436
            escape = True
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   437
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   438
        elif '\\$' in field :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   439
            pre, post = field.split('\\$', 1)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   440
            escape = True
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   441
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   442
        else :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   443
            pre, post = field.split('$', 1)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   444
        
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   445
        expr.append(pre)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   446
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   447
        if escape :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   448
            expr.append('$')
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   449
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   450
        else :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   451
            # meta-format
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   452
            fmt = '{value[%d]:0%d%s}' % (offset, width, base)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   453
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   454
            log.debug("field=%r -> pre=%r, fmt=%r, post=%r", field, expr, fmt, post)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   455
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   456
            expr.append(fmt)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   457
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   458
        field = post
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   459
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   460
    # final
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   461
    if field :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   462
        expr.append(field)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   463
    
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   464
    # combine
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   465
    expr = ''.join(expr)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   466
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   467
    log.debug("%s: %s", input, expr)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   468
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   469
    # processed
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   470
    def value_func (value) :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   471
        # magic wrapper to implement offsets
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   472
        return expr.format(value=OffsetValue(value))
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   473
    
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   474
    return value_func
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   475
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   476
def process_generate (line, origin, parts) :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   477
    """
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   478
        Process a 
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   479
            $GENERATE <start>-<stop>[/<step>] lhs [ttl] [class] type rhs [comment]
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   480
        directive into a series of ZoneResource's.
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   481
    """
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   482
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   483
    range = parts.pop(0)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   484
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   485
    # parse range
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   486
    if '/' in range :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   487
        range, step = range.split('/')
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   488
        step = int(step)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   489
    else :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   490
        step = 1
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   491
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   492
    start, stop = range.split('-')
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   493
    start = int(start)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   494
    stop = int(stop)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   495
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   496
    log.debug("  range: start=%r, stop=%r, step=%r", start, stop, step)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   497
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   498
    # inclusive
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   499
    range = xrange(start, stop + 1, step)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   500
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   501
    lhs_func = parse_generate_field(line, parts.pop(0))
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   502
    rhs_func = parse_generate_field(line, parts.pop(-1))
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   503
    body = parts
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   504
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   505
    for i in range :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   506
        # build
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   507
        parts = [lhs_func(i)] + body + [rhs_func(i)]
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   508
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   509
        log.debug(" %03d: %r", i, parts)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   510
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   511
        # parse
252
0ea4450fdd40 pvl.dns-zone: --serial
Tero Marttila <terom@paivola.fi>
parents: 251
diff changeset
   512
        yield ZoneRecord.parse(line, parts=parts, origin=origin)
247
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   513
250
65f0272ce458 pvl.dns.zone: move to ZoneLine/Record.load(file)
Tero Marttila <terom@paivola.fi>
parents: 248
diff changeset
   514
   
247
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   515
def reverse_ipv4 (ip) :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   516
    """
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   517
        Return in-addr.arpa reverse for given IPv4 prefix.
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   518
    """
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   519
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   520
    # parse
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   521
    octets = tuple(int(part) for part in ip.split('.'))
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   522
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   523
    for octet in octets :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   524
        assert 0 <= octet <= 255
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   525
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   526
    return '.'.join([str(octet) for octet in reversed(octets)] + ['in-addr', 'arpa'])
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   527
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   528
def reverse_ipv6 (ip6) :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   529
    """
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   530
        Return ip6.arpa reverse for given IPv6 prefix.
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   531
    """
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   532
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   533
    parts = [int(part, 16) for part in ip6.split(':')]
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   534
    parts = ['{0:04x}'.format(part) for part in parts]
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   535
    parts = ''.join(parts)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   536
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   537
    return '.'.join(tuple(reversed(parts)) + ( 'ip6', 'arpa'))
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   538
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   539
def fqdn (*parts) :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   540
    fqdn = '.'.join(parts)
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   541
    
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   542
    # we may be given an fqdn in parts
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   543
    if not fqdn.endswith('.') :
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   544
        fqdn += '.'
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   545
    
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   546
    return fqdn
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   547
08a63738f2d1 split pvl.dns-zone into pvl.dns.zone
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   548