def add_rrs(self, rrs_func, add_rr_func, admin_privilege, helpdesk_privilege, update_group=None): """ Add RR to data base Note use of rrs_func so that list of rrs is always refreshed in function. Can be supplied by using a no argument lambda function. This is so that in the case of a full ZI, rrs can be added to it, which is different to the case of incremental updates, where the list of RRs is constructed, and the rrs just added directly to the resource records table. """ db_session = self.db_session for rr_group in self.rr_group_data: for rr_data in rr_group['rrs']: # Remove unneeded keys from rr_data rr_data.pop('comment', None) rr_data.pop('zone_id', None) # Check privilege self.check_extra_data_privilege(rr_data, admin_privilege, helpdesk_privilege) rr = data_to_rr(self.name, rr_data) self.check_rr_consistency(rrs_func(), rr, rr_data, update_group) # Store rr_data for zi consistency checks self.put_zi_rr_data(str(rr), rr_data) # Add rr to SQLAlchemy data structures db_session.add(rr) # Sort out RR reference part of the data structure rr_ref_str = rr_data.get('reference') if rr_ref_str: self.check_reference_string(rr_ref_str) rr_ref = find_reference(db_session, rr_ref_str) rr.ref_id = rr_ref.id_ if rr_ref else None rr.reference = rr_ref # Sort out update_group if given if update_group: update_group.update_ops.append(rr) add_rr_func(rr) self.handle_auto_ptr_data(rr, rr_data)
def _queue_auto_ptr_data(self, auto_ptr_data): """ Queue auto PTR data as incremental updates against respective reverse zones. """ if not auto_ptr_data: return if not len(auto_ptr_data): return if not settings['auto_reverse']: return db_session = self.db_session # Create new update_group ug_dict = {} auto_ptr_privilege_flag = False for ptr_data in auto_ptr_data: # Ignore addresses we don't have reverse zone for query = db_session.query(ZoneSM)\ .join(ReverseNetwork)\ .filter(":address <<= reverse_networks.network")\ .params(address = ptr_data['address']) query = ZoneSM.query_is_not_deleted(query) query = ZoneSM.query_inc_updates(query) query = query.order_by(ReverseNetwork.network.desc())\ .limit(1) try: zone_sm = query.one() except NoResultFound: continue # Ignore invalid host names if not is_inet_hostname(ptr_data['hostname'], absolute=True, wildcard=False): log_error("Hostname '%s' is not a valid hostname." % ptr_data['hostname']) continue # Determine proposed update operation update_op = RROP_PTR_UPDATE_FORCE if ptr_data['force_reverse'] \ else RROP_PTR_UPDATE # Execute privilege checks ahead of time to save unnecessary churn # Better than needlessly going through whole rigamorole of # incremental update processing later on for no effect #1 See if old PTR exists to retrieve any RR reference # Both following also used lower down when generating RR_PTR label = label_from_address(ptr_data['address']) rr_ref = find_reference(db_session, ptr_data['reference'], raise_exc=False) # query for old record - this generates one select # Optimization - if check has previously suceeded, don't check # again as this is all checked further in if not auto_ptr_privilege_flag: qlabel= label[:label.rfind(zone_sm.name)-1] query = db_session.query(ResourceRecord)\ .filter(ResourceRecord.label == qlabel)\ .filter(ResourceRecord.zi_id == zone_sm.zi_candidate_id)\ .filter(ResourceRecord.disable == False)\ .filter(ResourceRecord.type_ == RRTYPE_PTR) old_rrs = query.all() old_rr = old_rrs[0] if len(old_rrs) else None # Check that we can proceed, only if check has not succeded yet if not check_auto_ptr_privilege(rr_ref, self.sectag, zone_sm, old_rr): if old_rr: log_debug("Zone '%s' - can't replace '%s' PTR" " as neither" " sectags '%s' vs '%s'" " references '%s' vs '%s'/'%s' (old PTR/rev zone)" "match ," " or values not given." % (zone_sm.name, old_rr.label, self.sectag.sectag, settings['admin_sectag'], rr_ref, old_rr.reference, zone_sm.reference)) else: log_debug("Zone '%s' - can't add '%s' PTR as neither" " sectags '%s' vs '%s'" " references '%s' vs '%s' (rev zone) match," " or values not given." % (zone_sm.name, qlabel, self.sectag.sectag, settings['admin_sectag'], rr_ref, zone_sm.reference)) continue auto_ptr_privilege_flag = True # Create a new update group if zone has not been seen before. try: update_group, zone_ttl = ug_dict.get(zone_sm) except (ValueError, TypeError): # Obtain reverse zone_ttl so PTR rrs can be created # Use candidate ZI as it always is available. # zi is published zi zi = self._get_zi(zone_sm.zi_candidate_id) if not zi: log_error("Zone '%s': does not have candidate zi." % zone_sm.name) continue zone_ttl = zi.zone_ttl update_group = new_update_group(db_session, None, zone_sm, None, ptr_only=True, sectag=self.sectag.sectag) ug_dict[zone_sm] = (update_group, zone_ttl) # Allocate RR_PTR update record rr = RR_PTR(label=label, zone_ttl=zone_ttl, rdata=ptr_data['hostname'], disable=ptr_data['disable'], domain=zone_sm.name, update_op=update_op) rr.ref_id = rr_ref.id_ if rr_ref else None rr.reference = rr_ref # Chain on RR_PTR update record update_group.update_ops.append(rr) # Flush everything to disk db_session.flush() # Issue zone refreshes to implement PTR changes for zone_sm in ug_dict: if zone_sm.is_disabled(): continue exec_zonesm(zone_sm, ZoneSMDoRefresh) # Make sure everything is committed db_session.commit()
def _queue_auto_ptr_data(self, auto_ptr_data): """ Queue auto PTR data as incremental updates against respective reverse zones. """ if not auto_ptr_data: return if not len(auto_ptr_data): return if not settings['auto_reverse']: return db_session = self.db_session # Create new update_group ug_dict = {} auto_ptr_privilege_flag = False for ptr_data in auto_ptr_data: # Ignore addresses we don't have reverse zone for query = db_session.query(ZoneSM)\ .join(ReverseNetwork)\ .filter(text(":address <<= reverse_networks.network"))\ .params(address = ptr_data['address']) query = ZoneSM.query_is_not_deleted(query) query = ZoneSM.query_inc_updates(query) query = query.order_by(ReverseNetwork.network.desc())\ .limit(1) try: zone_sm = query.one() except NoResultFound: continue # Ignore invalid host names if not is_inet_hostname( ptr_data['hostname'], absolute=True, wildcard=False): log_error("Hostname '%s' is not a valid hostname." % ptr_data['hostname']) continue # Determine proposed update operation update_op = RROP_PTR_UPDATE_FORCE if ptr_data['force_reverse'] \ else RROP_PTR_UPDATE # Execute privilege checks ahead of time to save unnecessary churn # Better than needlessly going through whole rigamorole of # incremental update processing later on for no effect #1 See if old PTR exists to retrieve any RR reference # Both following also used lower down when generating RR_PTR label = label_from_address(ptr_data['address']) rr_ref = find_reference(db_session, ptr_data['reference'], raise_exc=False) # query for old record - this generates one select # Optimization - if check has previously suceeded, don't check # again as this is all checked further in if not auto_ptr_privilege_flag: qlabel = label[:label.rfind(zone_sm.name) - 1] query = db_session.query(ResourceRecord)\ .filter(ResourceRecord.label == qlabel)\ .filter(ResourceRecord.zi_id == zone_sm.zi_candidate_id)\ .filter(ResourceRecord.disable == False)\ .filter(ResourceRecord.type_ == RRTYPE_PTR) old_rrs = query.all() old_rr = old_rrs[0] if len(old_rrs) else None # Check that we can proceed, only if check has not succeded yet if not check_auto_ptr_privilege(rr_ref, self.sectag, zone_sm, old_rr): if old_rr: log_debug( "Zone '%s' - can't replace '%s' PTR" " as neither" " sectags '%s' vs '%s'" " references '%s' vs '%s'/'%s' (old PTR/rev zone)" "match ," " or values not given." % (zone_sm.name, old_rr.label, self.sectag.sectag, settings['admin_sectag'], rr_ref, old_rr.reference, zone_sm.reference)) else: log_debug("Zone '%s' - can't add '%s' PTR as neither" " sectags '%s' vs '%s'" " references '%s' vs '%s' (rev zone) match," " or values not given." % (zone_sm.name, qlabel, self.sectag.sectag, settings['admin_sectag'], rr_ref, zone_sm.reference)) continue auto_ptr_privilege_flag = True # Create a new update group if zone has not been seen before. try: update_group, zone_ttl = ug_dict.get(zone_sm) except (ValueError, TypeError): # Obtain reverse zone_ttl so PTR rrs can be created # Use candidate ZI as it always is available. # zi is published zi zi = self._get_zi(zone_sm.zi_candidate_id) if not zi: log_error("Zone '%s': does not have candidate zi." % zone_sm.name) continue zone_ttl = zi.zone_ttl update_group = new_update_group(db_session, None, zone_sm, None, ptr_only=True, sectag=self.sectag.sectag) ug_dict[zone_sm] = (update_group, zone_ttl) # Allocate RR_PTR update record rr = RR_PTR(label=label, zone_ttl=zone_ttl, rdata=ptr_data['hostname'], disable=ptr_data['disable'], domain=zone_sm.name, update_op=update_op) rr.ref_id = rr_ref.id_ if rr_ref else None rr.reference = rr_ref # Chain on RR_PTR update record update_group.update_ops.append(rr) # Flush everything to disk db_session.flush() # Issue zone refreshes to implement PTR changes for zone_sm in ug_dict: if zone_sm.is_disabled(): continue exec_zonesm(zone_sm, ZoneSMDoRefresh) # Make sure everything is committed db_session.commit()