Example #1
0
    def _data_to_zi(self, name, zi_data, change_by, normalize_ttls=False,
                admin_privilege=False, helpdesk_privilege=False):
        """
        Construct a new ZI, RRS and comments, from zone_data.
        """
            
        def set_missing_zi_data():
            """
            Set missing fields in supplied zi_data to prevent problems
            """
            # Set ZI Zone ttl if not already set
            if 'zone_ttl' not in zi_data:
                zi_data['zone_ttl'] = zone_ttl
            # Set other SOA values in zi_data from defaults 
            # if they are not there. soa_ttl can be None
            for field in ['soa_mname', 'soa_rname', 'soa_refresh', 'soa_retry', 
                    'soa_expire', 'soa_minimum']:
                if not zi_data.get(field):
                    zi_data[field] = zone_cfg.get_row_exc(db_session, field,
                                                        sg=zone_sm.sg)
            # We always update serial number on zone udpdate/publish
            # but it is nicer and probably less troublesome to replace 
            # an existing serial number that may be out there
            if not zi_data.get('soa_serial'):
                if zone_sm.soa_serial:
                    zi_data['soa_serial'] = zone_sm.soa_serial
                else:
                    # Obviously a new zone
                    zi_data['soa_serial'] = new_zone_soa_serial(db_session)

        def check_zi_data():
            """
            Check incoming zi_data attributes for correctness
            """
            for field in ['soa_mname', 'soa_rname']:
                validate_zi_hostname(name, field, zi_data[field])
            for field in ['soa_refresh', 'soa_retry', 'soa_expire',
                    'soa_minimum', 'soa_ttl', 'zone_ttl']:
                if field == 'soa_ttl' and not zi_data.get(field):
                    # SOA TTL can be None
                    continue
                validate_zi_ttl(name, field, zi_data[field])
            for field in ['soa_serial']:
                if field == 'soa_serial' and zi_data.get(field, None) == None:
                    # SOA serial can be None
                    continue
                # Check incoming data type of soa_serial
                if not isinstance(zi_data['soa_serial'], int):
                    raise SOASerialTypeError(name)
                if not ( 0 < zi_data['soa_serial'] <= (2**32-1)):
                    # RFC 2136 Section 4.2 AO serial cannot be zero
                    raise SOASerialRangeError(name)
            
        # Function start
        db_session = self.db_session
        # Get zone_sm to get zone ID etc
        zone_sm = self._get_zone_sm(name)
        zone_id = zone_sm.id_
        
        # initialise data and zone consistency checking
        data_tools = DataTools(db_session, zone_sm)
        
        # Sort out a candidate value for zone_ttl so that RRs can be created
        zone_ttl = zi_data.get('zone_ttl',
                zone_cfg.get_row_exc(db_session, 'zone_ttl', sg=zone_sm.sg))
        zone_ttl_supplied = 'zone_ttl' in zi_data

        # Create comments, and set up comment IDs, and stuff for handlng
        # RR Groups zi_data structures
        data_tools.rr_data_create_comments(zi_data, zone_ttl)

        # Deal with ZI data problems, and supply defaults if missing
        set_missing_zi_data()
        check_zi_data()
        # This constructor call sets attributes in zi as well!
        zi = ZoneInstance(change_by=change_by, **zi_data)
        db_session.add(zi)
        apex_comment = data_tools.get_apex_comment()
        if apex_comment:
            zi.add_apex_comment(apex_comment)
        # Get zi.id_ zi.zone_id from database
        db_session.flush()
        
        # Add RRs to zi
        # Note use of lambda so that list of rrs is always refreshed in
        # function
        data_tools.add_rrs(lambda :zi.rrs, zi.add_rr,
                admin_privilege, helpdesk_privilege)

        # tie zi into data_structures
        zone_sm.all_zis.append(zi)
        zi.zone = zone_sm
        db_session.flush()
        # Normalise TTLs here
        if normalize_ttls and zone_ttl_supplied:
            zi.normalize_ttls()
        # Update SOA and NS records - can't hurt to do it here
        # This also cleans out any incoming apex NS records if
        # client should not be setting them.
        zi.update_apex(db_session)
        # Update Zone TTLs for clean initialisation
        zi.update_zone_ttls()
        db_session.flush()
        # Check zone consistency. Do this here as Apex RRs need to be complete.
        data_tools.check_zi_consistency(zi.rrs)
        return zi, data_tools.get_auto_ptr_data()
Example #2
0
    def main_process(self):
        """Main process editzone
        """
        def clean_up():
            if (tmp_file):
                os.unlink(tmp_file)

        tmp_file = ''
        # Get update session object
        error_str = ''
        try:
            update_session = DynDNSUpdate(settings['dns_server'],
                                    settings['dyndns_key_file'],
                                    settings['dyndns_key_name'],
                                    )
        except (socket.error, DynDNSCantReadKeyError, IOError) as exc:
            error_str = str(exc)
        # Process above error...
        if (error_str):
            log_error("%s" % error_str)
            sys.exit(os.EX_NOHOST)

        # Do AXFR to obtain current zone data
        msg = None
        try:
            (zone, dnskey_flag, nesc3param_flag) \
                = update_session.read_zone(self.zone_name)
        except NoSuchZoneOnServerError as exc:
            msg = str(exc)
        if msg:
            log_error(msg)
            sys.exit(os.EX_NOINPUT)
            
        # Only edit zone if not wrapping SOA serial number 
        if (not settings['wrap_serial'] and not settings['update_serial']
                and not settings['nsec3_seed'] and not settings['clear_nsec3']
                and not settings['clear_dnskey']):
            # Write zone out to a temporary file
            (fd, tmp_file) = tempfile.mkstemp(prefix=settings['process_name'] + '-',
                                    suffix='.zone')
            os.close(fd)
            zone.to_file(tmp_file)

            # Edit zone data
            old_stat = os.stat(tmp_file)
            editor = self._get_editor()
            try:
                output = check_call([editor, tmp_file])
            except CalledProcessError as exc:
                log_error("editor exited with '%s'." % exc.returncode)
                sys.exit(os.EX_SOFTWARE)
                
            new_stat = os.stat(tmp_file)
            if (not settings['force_update'] 
                    and old_stat[stat.ST_MTIME] == new_stat[stat.ST_MTIME]
                    and old_stat[stat.ST_SIZE] == new_stat[stat.ST_SIZE]
                    and old_stat[stat.ST_INO] == new_stat[stat.ST_INO]):
                log_info("File '%s' unchanged after editing - exiting." % tmp_file)
                clean_up()
                sys.exit(os.EX_OK)
     
            # Read in file and form zi structure
            zone = dns.zone.from_file(tmp_file, self.zone_name)
        # At the moment these values are just for the sake of it.
        zi = ZoneInstance(soa_refresh='5m', soa_retry='5m', soa_expire='7d', soa_minimum='600')
        for rdata in zone.iterate_rdatas():
            zi.add_rr(dnspython_to_rr(rdata))

        # Update Zone in DNS
        rcode, msg, soa_serial, *stuff = update_session.update_zone(
                            self.zone_name, zi, 
                            force_soa_serial_update=not(settings['no_serial']),
                            wrap_serial_next_time=settings['wrap_serial'],
                            nsec3_seed=settings['nsec3_seed'],
                            clear_nsec3=settings['clear_nsec3'],
                            clear_dnskey=settings['clear_dnskey']
                            )

        if rcode == RCODE_NOCHANGE:
            log_info(msg)
            sys.exit(os.EX_OK)

        # Delete temporary file
        clean_up()

        if rcode == RCODE_ERROR:
            log_warning(msg)
            sys.exit(os.EX_TEMPFAIL)
        elif rcode == RCODE_RESET:
            log_error(msg)
            sys.exit(os.EX_IOERR)
        elif rcode == RCODE_FATAL:
            log_error(msg)
            sys.exit(os.EX_IOERR)

        # Everything good - Lets GO!
        if (settings['verbose']):
            log_info(msg)
        else:
            log_debug(msg)
        sys.exit(os.EX_OK)
Example #3
0
    def _data_to_zi(self,
                    name,
                    zi_data,
                    change_by,
                    normalize_ttls=False,
                    admin_privilege=False,
                    helpdesk_privilege=False):
        """
        Construct a new ZI, RRS and comments, from zone_data.
        """
        def set_missing_zi_data():
            """
            Set missing fields in supplied zi_data to prevent problems
            """
            # Set ZI Zone ttl if not already set
            if 'zone_ttl' not in zi_data:
                zi_data['zone_ttl'] = zone_ttl
            # Set other SOA values in zi_data from defaults
            # if they are not there. soa_ttl can be None
            for field in [
                    'soa_mname', 'soa_rname', 'soa_refresh', 'soa_retry',
                    'soa_expire', 'soa_minimum'
            ]:
                if not zi_data.get(field):
                    zi_data[field] = zone_cfg.get_row_exc(db_session,
                                                          field,
                                                          sg=zone_sm.sg)
            # We always update serial number on zone udpdate/publish
            # but it is nicer and probably less troublesome to replace
            # an existing serial number that may be out there
            if not zi_data.get('soa_serial'):
                if zone_sm.soa_serial:
                    zi_data['soa_serial'] = zone_sm.soa_serial
                else:
                    # Obviously a new zone
                    zi_data['soa_serial'] = new_zone_soa_serial(db_session)

        def check_zi_data():
            """
            Check incoming zi_data attributes for correctness
            """
            for field in ['soa_mname', 'soa_rname']:
                validate_zi_hostname(name, field, zi_data[field])
            for field in [
                    'soa_refresh', 'soa_retry', 'soa_expire', 'soa_minimum',
                    'soa_ttl', 'zone_ttl'
            ]:
                if field == 'soa_ttl' and not zi_data.get(field):
                    # SOA TTL can be None
                    continue
                validate_zi_ttl(name, field, zi_data[field])
            for field in ['soa_serial']:
                if field == 'soa_serial' and zi_data.get(field, None) == None:
                    # SOA serial can be None
                    continue
                # Check incoming data type of soa_serial
                if not isinstance(zi_data['soa_serial'], int):
                    raise SOASerialTypeError(name)
                if not (0 < zi_data['soa_serial'] <= (2**32 - 1)):
                    # RFC 2136 Section 4.2 AO serial cannot be zero
                    raise SOASerialRangeError(name)

        # Function start
        db_session = self.db_session
        # Get zone_sm to get zone ID etc
        zone_sm = self._get_zone_sm(name)
        zone_id = zone_sm.id_

        # initialise data and zone consistency checking
        data_tools = DataTools(db_session, zone_sm)

        # Sort out a candidate value for zone_ttl so that RRs can be created
        zone_ttl = zi_data.get(
            'zone_ttl',
            zone_cfg.get_row_exc(db_session, 'zone_ttl', sg=zone_sm.sg))
        zone_ttl_supplied = 'zone_ttl' in zi_data

        # Create comments, and set up comment IDs, and stuff for handlng
        # RR Groups zi_data structures
        data_tools.rr_data_create_comments(zi_data, zone_ttl)

        # Deal with ZI data problems, and supply defaults if missing
        set_missing_zi_data()
        check_zi_data()
        # This constructor call sets attributes in zi as well!
        zi = ZoneInstance(change_by=change_by, **zi_data)
        db_session.add(zi)
        apex_comment = data_tools.get_apex_comment()
        if apex_comment:
            zi.add_apex_comment(apex_comment)
        # Get zi.id_ zi.zone_id from database
        db_session.flush()

        # Add RRs to zi
        # Note use of lambda so that list of rrs is always refreshed in
        # function
        data_tools.add_rrs(lambda: zi.rrs, zi.add_rr, admin_privilege,
                           helpdesk_privilege)

        # tie zi into data_structures
        zone_sm.all_zis.append(zi)
        zi.zone = zone_sm
        db_session.flush()
        # Normalise TTLs here
        if normalize_ttls and zone_ttl_supplied:
            zi.normalize_ttls()
        # Update SOA and NS records - can't hurt to do it here
        # This also cleans out any incoming apex NS records if
        # client should not be setting them.
        zi.update_apex(db_session)
        # Update Zone TTLs for clean initialisation
        zi.update_zone_ttls()
        db_session.flush()
        # Check zone consistency. Do this here as Apex RRs need to be complete.
        data_tools.check_zi_consistency(zi.rrs)
        return zi, data_tools.get_auto_ptr_data()