def lock(self): """ Tryies to write a lock file. Returns True if we get the lock, else return False. """ try: if not os.path.exists(os.path.dirname(self.LOCK_FILE)): os.makedirs(os.path.dirname(self.LOCK_FILE)) self.log("Attempting acquire mutext " "({0})...".format(self.LOCK_FILE)) self.lock_fd = open(self.LOCK_FILE, 'w+') fcntl.flock(self.lock_fd, fcntl.LOCK_EX | fcntl.LOCK_NB) self.log(self.format_title("Mutex Acquired")) return True except IOError, exc_value: self.lock_fd = None # IOError: [Errno 11] Resource temporarily unavailable if exc_value[0] == 11: self.log( "DNS build script attempted to acquire the " "build mutux but another process already has it." ) fail_mail( "An attempt was made to start the DNS build script " "while an instance of the script was already running. " "The attempt was denied.", subject="Concurrent DNS builds attempted.") return False else: raise
def build_zone_data(view, root_domain, soa, logf=None): """ This function does the heavy lifting of building a zone. It coordinates getting all of the data out of the db into BIND format. :param soa: The SOA corresponding to the zone being built. :type soa: SOA :param root_domain: The root domain of this zone. :type root_domain: str :returns public_file_path: The path to the zone file in the STAGEING dir :type public_file_path: str :returns public_data: The data that should be written to public_file_path :type public_data: str :returns view_zone_file: The path to the zone file in the STAGEING dir :type view_zone_file: str :param view_data: The data that should be written to view_zone_file :type view_data: str """ ztype = 'reverse' if root_domain.is_reverse else 'forward' if (soa.has_record_set(view=view, exclude_ns=True) and not root_domain.nameserver_set.filter(views=view).exists()): msg = ("The {0} zone has a records in the {1} view, but there are " "no nameservers in that view. A zone file for {1} won't be " "built. Use the search string 'zone=:{0} view=:{1}' to find " "the troublesome records".format(root_domain, view.name)) fail_mail(msg, subject="Shitty edge case detected.") logf('LOG_WARNING', msg) return '' domains = soa.domain_set.all().order_by('name') # Bulid the mega filter! domain_mega_filter = Q(domain=root_domain) for domain in domains: domain_mega_filter = domain_mega_filter | Q(domain=domain) rdomain_mega_filter = Q(reverse_domain=root_domain) for reverse_domain in domains: rdomain_mega_filter = rdomain_mega_filter | Q( reverse_domain=reverse_domain) soa_data = render_soa_only(soa=soa, root_domain=root_domain) try: if ztype == "forward": view_data = render_forward_zone(view, domain_mega_filter) else: view_data = render_reverse_zone(view, domain_mega_filter, rdomain_mega_filter) except View.DoesNotExist: view_data = "" if view_data: view_data = soa_data + view_data return view_data
def lock(self): """ Tryies to write a lock file. Returns True if we get the lock, else return False. """ try: if not os.path.exists(os.path.dirname(self.LOCK_FILE)): os.makedirs(os.path.dirname(self.LOCK_FILE)) self.log("Attempting acquire mutext " "({0})...".format(self.LOCK_FILE)) self.lock_fd = open(self.LOCK_FILE, 'w+') fcntl.flock(self.lock_fd, fcntl.LOCK_EX | fcntl.LOCK_NB) self.log(self.format_title("Mutex Acquired")) return True except IOError, exc_value: self.lock_fd = None # IOError: [Errno 11] Resource temporarily unavailable if exc_value[0] == 11: self.log("DNS build script attempted to acquire the " "build mutux but another process already has it.") fail_mail( "An attempt was made to start the DNS build script " "while an instance of the script was already running. " "The attempt was denied.", subject="Concurrent DNS builds attempted.") return False else: raise
def build_zone_data(view, root_domain, soa, logf=None): """ This function does the heavy lifting of building a zone. It coordinates getting all of the data out of the db into BIND format. :param soa: The SOA corresponding to the zone being built. :type soa: SOA :param root_domain: The root domain of this zone. :type root_domain: str :returns public_file_path: The path to the zone file in the STAGEING dir :type public_file_path: str :returns public_data: The data that should be written to public_file_path :type public_data: str :returns view_zone_file: The path to the zone file in the STAGEING dir :type view_zone_file: str :param view_data: The data that should be written to view_zone_file :type view_data: str """ ztype = "reverse" if root_domain.is_reverse else "forward" if soa.has_record_set(view=view, exclude_ns=True) and not root_domain.nameserver_set.filter(views=view).exists(): msg = ( "The {0} zone has a records in the {1} view, but there are " "no nameservers in that view. A zone file for {1} won't be " "built. Use the search string 'zone=:{0} view=:{1}' to find " "the troublesome records".format(root_domain, view.name) ) fail_mail(msg, subject="Shitty edge case detected.") logf("LOG_WARNING", msg) return "" domains = soa.domain_set.all().order_by("name") # Bulid the mega filter! domain_mega_filter = Q(domain=root_domain) for domain in domains: domain_mega_filter = domain_mega_filter | Q(domain=domain) rdomain_mega_filter = Q(reverse_domain=root_domain) for reverse_domain in domains: rdomain_mega_filter = rdomain_mega_filter | Q(reverse_domain=reverse_domain) soa_data = render_soa_only(soa=soa, root_domain=root_domain) try: if ztype == "forward": view_data = render_forward_zone(view, domain_mega_filter) else: view_data = render_reverse_zone(view, domain_mega_filter, rdomain_mega_filter) except View.DoesNotExist: view_data = "" if view_data: view_data = soa_data + view_data return view_data
def _lock_failure(self, pid): fail_mail( 'An attempt was made to start the DNS build script while an ' 'instance of the script was already running. The attempt was ' 'denied.', subject="Concurrent DNS builds attempted.") self.error('Failed to acquire lock on {0}. Process {1} currently ' 'has it.'.format(self.lock_file, pid))
def _lock_failure(self, pid): fail_mail( 'An attempt was made to start the DNS build script while an ' 'instance of the script was already running. The attempt was ' 'denied.', subject='Concurrent Cyder DNS builds attempted') self.error( 'Failed to acquire lock on {0}. Process {1} currently ' 'has it.'.format(self.lock_file, pid))
def _lock_failure(self, pid): self.log_err('Failed to acquire lock on {0}. Process {1} currently ' 'has it.'.format(self.lock_file, pid), to_stderr=False) fail_mail( 'An attempt was made to start the DHCP build script while an ' 'instance of the script was already running. The attempt was ' 'denied.', subject="Concurrent DHCP builds attempted.") super(DHCPBuilder, self)._lock_failure(pid)
def _lock_failure(self, pid): self.log_err( 'Failed to acquire lock on {0}. Process {1} currently ' 'has it.'.format(self.lock_file, pid), to_stderr=False) fail_mail( 'An attempt was made to start the DHCP build script while an ' 'instance of the script was already running. The attempt was ' 'denied.', subject="Concurrent DHCP builds attempted.") super(DHCPBuilder, self)._lock_failure(pid)
def stop_update_exists(self): """ Look for a file referenced by `STOP_UPDATE_FILE` and if it exists, cancel the build. """ if os.path.exists(self.STOP_UPDATE_FILE): msg = ("The STOP_UPDATE_FILE ({0}) exists. Build canceled. \n" "Reason for skipped build: \n" "{1}".format(self.STOP_UPDATE_FILE, open(self.STOP_UPDATE_FILE).read())) fail_mail(msg, subject="DNS builds have stoped") self.log(msg) return True
def build(self): try: with open(self.stop_file) as stop_fd: now = time.time() contents = stop_fd.read() last = os.path.getmtime(self.stop_file) msg = ('The stop file ({0}) exists. Build canceled.\n' 'Reason for skipped build:\n' '{1}'.format(self.stop_file, contents)) self.log_notice(msg, to_stderr=False) if (self.stop_file_email_interval is not None and now - last > self.stop_file_email_interval): os.utime(self.stop_file, (now, now)) fail_mail(msg, subject="DHCP builds have stopped") raise Exception(msg) except IOError as e: if e.errno == errno.ENOENT: # IOError: [Errno 2] No such file or directory pass else: raise try: for ip_type, files in (('4', self.files_v4), ('6', self.files_v6)): self.log_info('Building v{}...'.format(ip_type)) with open(os.path.join(self.stage_dir, files['target_file']), 'w') as f: for ctnr in Ctnr.objects.all(): f.write(ctnr.build_legacy_classes(ip_type)) for vrf in Vrf.objects.all(): f.write(vrf.build_vrf(ip_type)) for network in Network.objects.filter(ip_type=ip_type, enabled=True): f.write(network.build_subnet()) for workgroup in Workgroup.objects.all(): f.write(workgroup.build_workgroup(ip_type)) if files['check_file']: self.check_syntax(ip_type=ip_type, filename=files['check_file']) except: self.log(syslog.LOG_ERR, 'DHCP build failed.\nOriginal exception: ' + e.message) raise self.log_info('DHCP build successful')
def build(self): try: with open(self.stop_file) as stop_fd: now = time.time() contents = stop_fd.read() last = os.path.getmtime(self.stop_file) msg = ('The stop file ({0}) exists. Build canceled.\n' 'Reason for skipped build:\n' '{1}'.format(self.stop_file, contents)) self.log_notice(msg, to_stderr=False) if (self.stop_file_email_interval is not None and now - last > self.stop_file_email_interval): os.utime(self.stop_file, (now, now)) fail_mail(msg, subject="DHCP builds have stopped") raise Exception(msg) except IOError as e: if e.errno == errno.ENOENT: # IOError: [Errno 2] No such file or directory pass else: raise try: for ip_type, files in (('4', self.files_v4), ('6', self.files_v6)): self.log_info('Building v{}...'.format(ip_type)) with open(os.path.join(self.stage_dir, files['target_file']), 'w') as f: for ctnr in Ctnr.objects.all(): f.write(ctnr.build_legacy_classes(ip_type)) for vrf in Vrf.objects.all(): f.write(vrf.build_vrf(ip_type)) for network in Network.objects.filter( ip_type=ip_type, enabled=True): f.write(network.build_subnet()) for workgroup in Workgroup.objects.all(): f.write(workgroup.build_workgroup(ip_type)) if files['check_file']: self.check_syntax( ip_type=ip_type, filename=files['check_file']) except: self.log(syslog.LOG_ERR, 'DHCP build failed.\nOriginal exception: ' + e.message) raise self.log_info('DHCP build successful')
def build(self): try: with open(self.stop_file) as stop_fd: now = time.time() contents = stop_fd.read() last = os.path.getmtime(self.stop_file) msg = ('The stop file ({0}) exists. Build canceled.\n' 'Reason for skipped build:\n' '{1}'.format(self.stop_file, contents)) self.log_notice(msg, to_stderr=False) if (self.stop_file_email_interval is not None and now - last > self.stop_file_email_interval): os.utime(self.stop_file, (now, now)) fail_mail(msg, subject="DHCP builds have stopped") raise Exception(msg) except IOError as e: if e.errno == 2: # IOError: [Errno 2] No such file or directory pass else: raise self.log_info('Building...') try: with open(os.path.join(self.stage_dir, self.target_file), 'w') \ as f: for ctnr in Ctnr.objects.all(): f.write(ctnr.build_legacy_classes()) for vrf in Vrf.objects.all(): f.write(vrf.build_vrf()) for network in Network.objects.filter(enabled=True): f.write(network.build_subnet()) for workgroup in Workgroup.objects.all(): f.write(workgroup.build_workgroup()) except: self.error() if self.check_file: self.check_syntax() self.log_info('DHCP build successful')
def build(self, force=False): try: with open(self.stop_file) as stop_fd: now = time.time() contents = stop_fd.read() last = os.path.getmtime(self.stop_file) msg = ("The stop file ({0}) exists. Build canceled.\n" "Reason for skipped build:\n" "{1}".format(self.stop_file, contents)) self.log_notice(msg) if (self.stop_file_email_interval is not None and now - last > self.stop_file_email_interval): os.utime(self.stop_file, (now, now)) fail_mail(msg, subject="DNS builds have stopped") raise Exception(msg) except IOError as e: if e.errno != 2: # IOError: [Errno 2] No such file or directory raise self.log_info('Building...') try: remove_dir_contents(self.stage_dir) self.dns_tasks = self.get_scheduled() if not self.dns_tasks and not force: self.log_info('Nothing to do!') return # zone files soa_pks_to_rebuild = set(int(t.task) for t in self.dns_tasks) self.build_config_files(self.build_zone_files(soa_pks_to_rebuild, force=force)) self.log_info('DNS build successful') except Exception as e: self.log(syslog.LOG_ERR, 'DNS build failed.\nOriginal exception: ' + e.message) raise
def build(self, force=False): try: with open(self.stop_file) as stop_fd: now = time.time() contents = stop_fd.read() last = os.path.getmtime(self.stop_file) msg = ("The stop file ({0}) exists. Build canceled.\n" "Reason for skipped build:\n" "{1}".format(self.stop_file, contents)) self.log_notice(msg) if (self.stop_file_email_interval is not None and now - last > self.stop_file_email_interval): os.utime(self.stop_file, (now, now)) fail_mail(msg, subject="DNS builds have stopped") raise Exception(msg) except IOError as e: if e.errno != errno.ENOENT: # IOError: [Errno 2] No such file or directory raise self.log_info('Building...') try: remove_dir_contents(self.stage_dir) self.dns_tasks = self.get_scheduled() if not self.dns_tasks and not force: self.log_info('Nothing to do!') return # zone files soa_pks_to_rebuild = set(int(t.task) for t in self.dns_tasks) self.build_config_files( self.build_zone_files(soa_pks_to_rebuild, force=force)) self.log_info('DNS build successful') except Exception as e: self.log(syslog.LOG_ERR, 'DNS build failed.\nOriginal exception: ' + e.message) raise
def build_zone_data(view, root_domain, soa, logf): """ This function does the heavy lifting of building a zone. It coordinates getting all of the data out of the db into BIND format. :param soa: The SOA corresponding to the zone being built. :type soa: SOA :param root_domain: The root domain of this zone. :type root_domain: str :returns public_file_path: The path to the zone file in the STAGEING dir :type public_file_path: str :returns public_data: The data that should be written to public_file_path :type public_data: str :returns view_zone_file: The path to the zone file in the STAGEING dir :type view_zone_file: str :param view_data: The data that should be written to view_zone_file :type view_data: str """ ztype = 'reverse' if root_domain.is_reverse else 'forward' if (soa.has_record_set(view=view, exclude_ns=True) and not root_domain.nameserver_set.filter(views=view).exists()): msg = ("The {0} zone has at least one record in the {1} view, but " "there are no nameservers in that view. A zone file for {1} " "won't be built. Use the search string 'zone=:{0} view=:{1}' " "to find the troublesome record(s)".format( root_domain, view.name)) fail_mail(msg, subject="Record(s) without NS records can't be built") logf(msg) return '' domains = soa.domain_set.all().order_by('name') # Build the mega filter! domain_mega_filter = Q(domain=root_domain) for domain in domains: domain_mega_filter = domain_mega_filter | Q(domain=domain) rdomain_mega_filter = Q(reverse_domain=root_domain) for reverse_domain in domains: rdomain_mega_filter = rdomain_mega_filter | Q( reverse_domain=reverse_domain) soa_data = render_soa_only(soa=soa, root_domain=root_domain) if root_domain.ip_type == '4': range_set = (root_domain.get_related_ranges().filter( views__name=view.name).order_by('start_upper', 'start_lower')) else: range_set = [] try: if ztype == "forward": view_data = render_forward_zone(view, domain_mega_filter) else: ip_type = (IP_TYPE_6 if root_domain.name.endswith('ip6.arpa') else IP_TYPE_4) view_data = render_reverse_zone(view, domain_mega_filter, rdomain_mega_filter, ip_type=ip_type, range_set=range_set) except View.DoesNotExist: view_data = "" if view_data: view_data = soa_data + view_data return view_data
def build_zone_data(view, root_domain, soa, logf): """ This function does the heavy lifting of building a zone. It coordinates getting all of the data out of the db into BIND format. :param soa: The SOA corresponding to the zone being built. :type soa: SOA :param root_domain: The root domain of this zone. :type root_domain: str :returns public_file_path: The path to the zone file in the STAGEING dir :type public_file_path: str :returns public_data: The data that should be written to public_file_path :type public_data: str :returns view_zone_file: The path to the zone file in the STAGEING dir :type view_zone_file: str :param view_data: The data that should be written to view_zone_file :type view_data: str """ ztype = 'reverse' if root_domain.is_reverse else 'forward' if (soa.has_record_set(view=view, exclude_ns=True) and not root_domain.nameserver_set.filter(views=view).exists()): msg = ("The {0} zone has at least one record in the {1} view, but " "there are no nameservers in that view. A zone file for {1} " "won't be built. Use the search string 'zone=:{0} view=:{1}' " "to find the troublesome record(s)" .format(root_domain, view.name)) fail_mail(msg, subject="Record(s) without NS records can't be built") logf(msg) return '' domains = soa.domain_set.all().order_by('name') # Build the mega filter! domain_mega_filter = Q(domain=root_domain) for domain in domains: domain_mega_filter = domain_mega_filter | Q(domain=domain) rdomain_mega_filter = Q(reverse_domain=root_domain) for reverse_domain in domains: rdomain_mega_filter = rdomain_mega_filter | Q( reverse_domain=reverse_domain) soa_data = render_soa_only(soa=soa, root_domain=root_domain) if root_domain.ip_type == '4': range_set = (root_domain.get_related_ranges() .filter(views__name=view.name) .order_by('start_upper', 'start_lower')) else: range_set = [] try: if ztype == "forward": view_data = render_forward_zone(view, domain_mega_filter) else: ip_type = (IP_TYPE_6 if root_domain.name.endswith('ip6.arpa') else IP_TYPE_4) view_data = render_reverse_zone( view, domain_mega_filter, rdomain_mega_filter, ip_type=ip_type, range_set=range_set) except View.DoesNotExist: view_data = "" if view_data: view_data = soa_data + view_data return view_data