def run(self): msg = '' is_success = True try: if self.group_name != CONF.host_group: raise UpdaterErr( u'Host %s group not match: local %s, param: %s' % (CONF.host_ip, CONF.host_group, self.group_name)) if self.update_type == 'named.conf': self.update_named() elif self.update_type == 'acl': self.update_acl() elif self.update_type == 'zone': self.init_zone() else: raise UpdaterErr('No worker for this type of update: %s' % self.update_type) except Exception as e: send_alarm_email(u'更新文件失败\n主机: %s\n, 类型: %s, 原因: %s' % (_get_local_hostname(), self.update_type, e)) log.exception(e) msg = str(e) is_success = False deploy_id = self.kwargs.get('deploy_id', None) if deploy_id: DnsdbApi.update_deploy_info(deploy_id, is_success, msg)
def check_necessary_options(): needed_conf_options = { 'etc': ["log_dir", "tmp_dir", "backup_dir", "pidfile", 'env'], 'MAIL': ['from_addr', 'server', 'port', 'info_list', 'alert_list'], } for section, options in needed_conf_options.items(): if not hasattr(CONF, section): raise UpdaterErr(message=section + " section not found.") sec = getattr(CONF, section) for op in options: if not hasattr(sec, op): raise UpdaterErr(message="%s.%s option not found." % (section, op)) if op.endswith('_dir'): dir_path = getattr(sec, op) if not os.path.exists(dir_path): try: make_tmp_dir(dir_path) except Exception as e: raise UpdaterErr( message='make directory error: %s, reason: %s' % (dir_path, e)) if not os.path.isdir(dir_path): raise UpdaterErr( message= '%s=%s need to be a directory, pleace change etc/beta/dnsdb-updater.conf' % (op, dir_path))
def _dnsdb_resp_wrapper(resp, req): try: resp = resp.json() except Exception as ex: raise UpdaterErr( u'DnsdbApi request error: %s' % ex, 500, detail=dict( request=req, ex=str(ex), reason=resp.reason, status=resp.status_code), msg_ch=u'DnsdbApi调用失败') if int(resp.get('status', 200)) != 200 or resp.get('errcode', 0) != 0: raise UpdaterErr(u'DnsdbApi调用失败: %s' % json.dumps(resp), 400, json.dumps(resp)) return resp
def reload_and_backup_zones(zone_file_dict): for zone, file_info in zone_file_dict.iteritems(): if os.system("cp -f %s %s >/dev/null 2>&1" % (file_info['src'], file_info['dst'])) != 0: raise UpdaterErr("Failed to copy file: %s" % file_info['src']) if CONF.etc.env != 'dev': rndc_debugfile = make_debugfile_path("rndc") if os.system("%s reload %s >%s 2>&1" % (CONF.bind_conf.rndc, zone, rndc_debugfile)) != 0: error_log = backup_debug_file(rndc_debugfile) raise UpdaterErr("Failed to reload:%s, see %s." % (zone, error_log)) log.info("Reloaded %s." % zone) backup_file(zone, file_info['src'])
def _get_serial_from_zone_file(path): pgrep = sp.Popen(split("grep -i 'serial' %s" % path), stdout=sp.PIPE, stderr=sp.PIPE) exit_code = pgrep.wait() if int(exit_code) != 0: raise UpdaterErr("Unable to grep serial line.") grep_ouput = pgrep.communicate()[0] pattern = re.match('^[^\d]*(\d*).*', grep_ouput) if pattern is None: raise UpdaterErr("Unable grep serial.") current_serial = pattern.group(1) log.info("Got serial %s from %s." % (current_serial, path)) return current_serial
def update_named_conf(group_name): named_conf = DnsdbApi.get_named_conf(group_name)['data'] named_dir = _get_named_dir() new_name_path = os.path.join(named_dir, group_name) to_use_file = '{0}_used'.format(new_name_path) with open(new_name_path, 'w') as f: f.write(named_conf) shutil.copy(new_name_path, to_use_file) # 如果是local dns 检查前先获取本机ip 将listen-on {ip};添加到option中 if _is_local_dns(): output, status = os.system( "ifconfig | grep inet | awk '{print $2}' | awk -F '/' '{print $1}' | grep -E '(^127\.|^192\.|^10\.)'" ) iplist = [ip.strip() for ip in output.split('\n')] if len(iplist) <= 1: raise UpdaterErr('listen ip %s replace failed' % ','.join(iplist)) log.info('listen ip: %s' % iplist) with open(to_use_file) as f: content = f.read() content = content.replace('#localdns_listen_mark', 'listen-on {%s;};' % (';'.join(iplist))) open(to_use_file, 'w').write(content) check_named_conf(to_use_file) if can_reload(group_name): copy_named_conf(to_use_file) reload_conf()
def make_zone_file(zone, filename, serial, header, record_list): try: with open(filename, 'w') as f: f.writelines(header) run_command_with_code( split('sed -i "" "s/pre_serial/%s/" %s' % (str(serial), filename))) with open(filename, 'a') as f: for item in record_list: name = item["name"].replace("." + zone, "") record = item["record"] if item["type"] == 'CNAME': record = record + "." ttl = 0 if "ttl" in item: ttl = int(item["ttl"]) if ttl == 0: f.write("%s \t IN \t %s \t %s\n" % (name, item["type"], record)) else: f.write("%s \t %d \t IN \t %s \t %s\n" % (name, int(ttl), item["type"], record)) except Exception as e: log.error(e) raise UpdaterErr('Create zone file failed: %s' % e)
def reload_conf(): if CONF.etc.env == 'dev': return status, output = commands.getstatusoutput('%s reload' % CONF.bind_conf.rndc) if status == 0: log.info('rndc reload success') else: raise UpdaterErr('reload named.conf failed: %s' % output)
def check_named_conf(named_file): if CONF.etc.env == 'dev': return status, output = commands.getstatusoutput('%s %s' % (CONF.bind_conf.named_checkconf, named_file)) if status == 0: log.info('check %s ok' % named_file) else: raise UpdaterErr('check %s fail, %s' % (named_file, output))
def _get_serial_from_zone_file(path): grep_ouput, exit_code = run_command_with_code("grep -i 'serial' %s" % path) pattern = re.match('^[^\d]*(\d*).*', grep_ouput) if pattern is None: raise UpdaterErr("Unable grep serial.") current_serial = pattern.group(1) log.info("Got serial %s from %s." % (current_serial, path)) return current_serial
def _create_pid_file(): global fp pidfile = CONF.etc.pidfile if pidfile is None: raise UpdaterErr("No pidfile option found in config file.") try: fp = open(pidfile, 'w') # LOCK_EX /* exclusive lock */ # LOCK_NB * don't block when locking */ fcntl.flock(fp, fcntl.LOCK_EX | fcntl.LOCK_NB) fp.truncate() pid = os.getpid() fp.write(str(pid)) fp.flush() except Exception as e: raise UpdaterErr( "Failed to lock pidfile, perhaps named_updater is already running." )
def checkzone(zone, zonefile_path): if CONF.etc.env == 'dev': return cmd = CONF.bind_conf.named_zonecheck debug_file = make_debugfile_path("named-checkzone") if os.system("%s -k fail %s %s >%s 2>&1" % (cmd, zone, zonefile_path, debug_file)) != 0: error_log = backup_debug_file(debug_file) raise UpdaterErr("zone syntax check did not return success for %s, see %s." % (zone, error_log)) log.info("named-checkzone said %s is ok." % zone)
def copy_named_conf(named_file): named_path = _get_named_path() # 备份 backup_file('named', named_path) status, output = commands.getstatusoutput( 'cp %s %s && chown named:named %s' % (named_file, named_path, named_path)) if status == 0: log.info('update name.conf ok') else: raise UpdaterErr('copy_named_conf failed: %s' % output)
def run_command_with_code(cmd, check_exit_code=True): """Runs a command in an out-of-process shell. Returns the output of that command. Working directory is self.root. """ proc = sp.Popen(cmd, stdout=sp.PIPE, stderr=sp.PIPE) output = proc.communicate()[0] if check_exit_code and proc.returncode != 0: raise UpdaterErr('Command "%s" failed.\n%s' % (' '.join(cmd), output)) return output, proc.returncode
def copy_named_conf(named_file): named_path = _get_named_path() # 备份 backup_file('named', named_path) status, output = commands.getstatusoutput( f'cp {named_file} {named_path} && chown {CONF.bind_default.user}:{CONF.bind_default.group} {named_path}' ) if status == 0: log.info('update name.conf ok') else: raise UpdaterErr('copy_named_conf failed: %s' % output)
def _check_necessary_options(): needed_conf_options = { 'etc': ["log_dir", "tmp_dir", "backup_dir", "pidfile", 'env'], 'MAIL': ['from_addr', 'server', 'port', 'info_list', 'alert_list'], } for section, options in needed_conf_options.iteritems(): if not hasattr(CONF, section): raise UpdaterErr(message=section + " section not found.") sec = getattr(CONF, section) for op in options: if not hasattr(sec, op): raise UpdaterErr(message="%s.%s option not found." % (section, op)) if op.endswith('_dir'): dir_path = getattr(CONF.etc, op) if not os.path.exists(dir_path) or not os.path.isdir(dir_path): raise UpdaterErr(message='No such directory: %s' % dir_path)
def _get_handler(): mapping = { 'ViewMaster': 'dns_updater.workers.view_worker', 'default': 'dns_updater.workers.zone_worker' } zone_group = CONF.host_group if not zone_group.endswith('Master'): raise UpdaterErr('%s, slave group does not need to start updater.' % zone_group) # dnsdb请求zone信息 module = importlib.import_module( mapping.get(zone_group, mapping['default'])) return module.handler
def run_command_with_code(cmd, check_exit_code=True): """Runs a command in an out-of-process shell. Returns the output of that command. Working directory is self.root. """ proc = sp.Popen(split(cmd), stdout=sp.PIPE, stderr=sp.PIPE, encoding='utf-8') output = proc.communicate()[0] retcode = proc.returncode if check_exit_code and retcode != 0: raise UpdaterErr('Command "%s" failed.\n%s' % (cmd, output)) log.info('Command "%s" success.' % ' '.join(cmd)) return output, retcode
def main_loop(self): raise UpdaterErr('This function has not been implemented yet')