コード例 #1
0
ファイル: dns_api.py プロジェクト: lexlinden/jinx-api
def refresh_zone_history(request):
    """Update DNS zone file history with the current live zones.
    
    This API call can be used to notify Jinx of an update made directly to a
    zone.
    """
    
    acquire_lock("dns")
    hg = init_repository(jinx_global_settings['DNS_REPOSITORY_URL'])
    
    zone_list = hg.get_file("zone-list") or ""
    my_zones = [dns.name.from_text(zone) for zone in zone_list.splitlines()]
    
    _store_zone_history(my_zones, hg)
    
    hg.commit("jinx: refreshed zones from master nameserver (requested by %s)" % request.META['REMOTE_USER'])
    hg.push()
    
    return True
コード例 #2
0
ファイル: dns_api.py プロジェクト: lexlinden/jinx-api
def update_dns_records(request, add_rrsets, delete_rrsets, modify_rrsets, comments, description, simulate=False):
    """Perform a DNS update.
    
    This API call provides the ability to modify DNS records in one or more 
    zones.  Updates are processed on "resource record sets" (RRsets), which 
    are groups of records with the same name and type.  For example, consider 
    this zone file snippet:
    
    foo    300 IN A 1.1.1.1
           300 IN A 1.1.1.2
               IN TXT "foo round-robin"
    
    This comprises _two_ RRsets: one for the two A records together, and a
    second for the TXT record.
    
    Operations must be requested on entire RRsets.  For example, if I want to
    add another A record to the round-robin above, I'd need to specify a 
    modification of the existing RRset, replacing it with a set containing
    all three records.  Similarly, if I want to change one IP in the round-
    robin, I request to replace the entire RRset with a modified one.  I'm
    not allowed to add or modify just one record of an RRset.
    
    When deleting an RRset, the client must include a complete definition of
    the existing RRset.  Jinx will verify that the RRset exists and contains
    exactly the data the client expects.  If it does not, the update is
    rejected because Jinx presumes another client has modified the zone
    while this client was preparing its modification.
    
    RRset modifications are simply processed as a delete and an add.  Just as
    for a delete, the current data in the RRset must be completely specified,
    and Jinx will reject the modification if the current data in DNS does not
    match.
    
    The data formats for the add_rrsets and deletE_rrsets are as follows:
    
        [
            ["foo.lindenlab.com.",  300, "IN", "A", [ '1.1.1.1', '1.1.1.2' ] ]
            ["foo.lindenlab.com.", 3600, "IN", "TXT", [ "foo round-robin" ] ]
        ]
        
    The argument is a list of RRsets.  Each RRset is a list, containing the 
    domain name (fully-qualified with trailing dot), TTL, class, type, and
    values.  The values are always a list, even for single records.  This 
    allows for round-robins to be specified.
    
    modify_rrsets is a bit different, to allow for both the old and new RRset
    data to be specified.  For example, to modify the "foo" RRset to change
    1.1.1.2 to 1.1.1.3, the client would pass this:
    
        [
            ["foo.lindenlab.com.", [300, "IN", "A", [ '1.1.1.1', '1.1.1.2' ] ],
                                   [300, "IN", "A", [ '1.1.1.1', '1.1.1.3' ] ]
            ]
        ]
    
    The name is specified only once because an RRset must always be replaced
    with another of the same name -- otherwise it's a deletion and an addition
    of an unrelated RRset.  The old data comes next, enclosed in a list.  The
    new data comes after that, also enclosed in a list.
    
    Assuming all of the client's notions of the current state of DNS pan out,
    Jinx will update the DNS zone as requested.  It will also record the new
    comments and store the entire change in its version tracking backend for
    later review.
    
    Arguments:
        add_rrsets -- A list of RRsets to add.
        delete_rrsets -- A list of RRsets to delete.
        modify_rrsets -- A list of RRsets to modify (delete then add).
        comments -- A dict of record comments to apply.  Keys are the FQDN 
          (including trailing dot) of the record set to attach the comment to.
          Each value is a string or None (indicating that any existing comment 
          should be deleted).
        description -- A textual description of the change (commit message).
        simulate -- If True, updates will not be sent to the DNS server,
          history will not be updated, and comments will not be updated.  Use
          this to just run checks on your updates.
    
    Returns:
        The number of zones updated.
    
    Exceptions Raised:
        JinxInvalidStateError -- A condition or assumption of the client was 
          invalid.  For example, the client tried to delete a record that did
          not exist, or modify a record that had a value different from what
          the client expected.  
          
          This exception can also be raised if certain DNS parse errors are
          encountered, such as an attempt to create a CNAME record and an A
          record with the same name (which is disallowed by the DNS RFC).  This
          can happen due to user error or if two users are preparing DNS 
          modifications at around the same time.
        
        JinxInvalidRequestError -- Something was incorrect about the records passed
          by the client (e.g. a TTL that's not a number).  See exception text
          for a description.
    """

#    try:

    acquire_lock("dns")
    
    hg = init_repository(jinx_global_settings['DNS_REPOSITORY_URL'])
    
    zone_list = hg.get_file("zone-list") or ""
    my_zones = [dns.name.from_text(zone) for zone in zone_list.splitlines()]
    
    name_re = re.compile('^[*0-9a-zA-Z_][-*0-9a-zA-Z_.]*\.')
    
    # Convert arguments into dnspython RRsets:
    add_rrsets, delete_rrsets = _parse_rrsets(add_rrsets, delete_rrsets, modify_rrsets)
    
    # Make sure every updated record is for a zone I handle.
    _check_record_names(add_rrsets + delete_rrsets, my_zones)
    
    # Make sure the comment changes are for records in zones I handle.
    _check_comment_names(comments, my_zones)
    
    updates = _prepare_dns_updates(add_rrsets, delete_rrsets, my_zones)
    
    _check_zones(updates.keys(), add_rrsets, delete_rrsets)
    
    if not simulate:
        _send_updates(updates.values())
        
        _store_zone_history(updates.keys(), hg)
        _update_comments(comments, hg)
        
        hg.commit("%s: %s" % (request.META['REMOTE_USER'], description))
        hg.push()
    
    # The lock on "dns" will be released automatically when the transaction is
    # committed.
    
    return len(updates)