def __init__(self, work_uuid, work_name, oper, exec_mode, options, inventory_content, describe, yaml_content='', log_router=None, module_name=None, module_args=None, pattern=None , display=None, mongoclient=None): ''' 实现回调信息写入MongoDB等后端,进行持久化 :parm work_name:工作名称 oper:操作者 op_mode:操作类型,adhoc、playbook等 prov_parm:用户提供的参数,对机密数据进行简单处理 handled_para:用户提供的参数处理后的数据 yamlfile:yaml文件,仅局限于playbook log_router:写入日志路由 yamldata:yaml文件数据 ''' if not log_router: self.log_router = Routing_Logging(mongoclient=mongoclient) else : self.log_router = log_router self.work_uuid = work_uuid self.work_name = work_name self.exec_mode = exec_mode self.oper = oper self.yaml_content = yaml_content self.pattern = pattern self.module_name = module_name self.module_args = module_args self.options = options self.inventory_content = inventory_content self.result = { 'mode' : self.exec_mode, 'name' : self.work_name, 'uuid' : self.work_uuid, 'describe' : describe, 'create_date' : timestamp2datetime(stamp=time.time() , fmt='%Y-%m-%d'), 'create_time' : timestamp2datetime(stamp=time.time() , fmt='%Y-%m-%d %H:%M'), 'options':self.options, 'inventory_content': self.inventory_content, 'create_ts': round(time.time(), 3), } if self.exec_mode == 'adhoc' : self.result['pattern'] = self.pattern self.result['module_name'] = self.module_name self.result['module_args'] = self.module_args if self.exec_mode == 'playbook' : self.result['yaml_content'] = self.yaml_content self.log_dict = { 'level':'info', 'dest' : 'mongo', 'mongo' : self.oper + '.ansible.callback', } super(Write_Storage, self).__init__(display)
def summary(self): ''' 用户列表 ''' result = self.get_userinfo() get_field = ['username', 'name', 'isalive', 'lastlogin_time'] if not result: self.logger.info('查询失败或者没有用户,原因:' + str(result[1])) return (False, result[1]) else: query_list = [] for data in result: temp_list = [] if 'lastlogin_time' not in data: data['lastlogin_time'] = '-' for key in get_field: value = data[key] if key == 'lastlogin_time': if value != '-': value = timestamp2datetime(value) if key == 'isalive': if value: value = '是' else: value = '否' temp_list.append(value) query_list.append(temp_list) return (True, query_list)
def write(self, content, oper, log_dict={}): ''' 写入日志,追加方式 日志格式为 写入年月日 时分秒 写入时间戳 日志级别 操作用户 日志内容(字符串或者字典) :参数 log_dict : 日志字典 oper : 操作者 content : 日志内容 isdubug:是否为debug日志 :返回 一个元组,(False,原因)或者(True, 文件名) ''' if not content : return (False , '日志内容为空!!!!') from library.utils.dict import _2dot content = _2dot(content) try : content = json.dumps(content) except : content = str(content) # json的标准格式:要求必须 只能使用双引号作为键 或者 值的边界符号,不能使用单引号,而且“键”必须使用边界符(双引号) if log_dict == {} or not log_dict or not isinstance(log_dict, dict) : log_dict = self.default_log_dict try : dest = log_dict['dest'] if dest != 'file': level = self.default_log_dict['level'] log_file = self.default_log_dict['file'] else : level = log_dict['level'] if level not in level_list : level = self.default_log_dict['level'] log_file = log_dict['file'] except : level = self.default_log_dict['level'] log_file = self.default_log_dict['file'] if not oper : oper = 'unknown' from library.utils.time_conv import timestamp2datetime curl_time = timestamp2datetime(fmt='%Y-%m-%d %H:%M:%S') message = curl_time + self.delimiter + str(time.time()) + self.delimiter + level + self.delimiter + oper + self.delimiter + content + '\n' if level == 'debug' : from library.utils.traceback import get_traceback caller_str = get_traceback() message = message + caller_str + '\n' from library.utils.file import write_file result = write_file(log_file , 'a' , message, force=True , backup=False) return result
def detail(self, username): ''' 查看用户详细信息 ''' old_user_dict = self.get_userinfo(username=username) if not old_user_dict: self.logger.error('查看用户' + username + '详细信息失败,原因:用户不存在') return (False, '用户' + username + '不存在') result = self.mongoclient.find(self.userinfo_mongocollect, condition_dict={'username': username}) if not result[0]: self.logger.error('查看用户' + username + '详细信息失败,原因:' + str(result[1])) return (False, '查询用户失败,' + str(result[1])) detail_mess = result[1][0] if detail_mess['isalive']: isalive = '是' else: isalive = '否' if 'create_time' in detail_mess: create_date = timestamp2datetime(detail_mess['create_time']) else: create_date = timestamp2datetime(detail_mess['add_time']) if 'lastlogin_time' in detail_mess: lastlogin_time = timestamp2datetime(detail_mess['lastlogin_time']) else: lastlogin_time = '-' if 'lastedit_time' in detail_mess: lastedit_time = timestamp2datetime(detail_mess['lastedit_time']) else: lastedit_time = '-' if 'creater' in detail_mess: creater = detail_mess['creater'] else: creater = '-' if 'lastediter' in detail_mess: lastediter = detail_mess['lastediter'] else: lastediter = '-' if 'level' in detail_mess: level = detail_mess['level'] else: level = '-' detail_dict = { u'真实姓名': detail_mess['name'], u'联系方式': detail_mess['contact'], u'是否激活': isalive, u'创建者': creater, u'创建时间': create_date, u'上次登录时间': lastlogin_time, u'上次编辑用户': lastediter, u'上次编辑时间': lastedit_time, u'是否激活': isalive, u'权限': level } level_show = {0: '初级运维', 1: '高级运维', 2: '管理员'} show_list = [('真实姓名', detail_mess['name']), ('联系方式', detail_mess['contact']), ('是否激活', isalive), ('创建者', creater), ('创建时间', create_date), ('上次登录时间', lastlogin_time), ('上次编辑用户', lastediter), ('上次编辑时间', lastedit_time), ('是否激活', isalive), ('权限', level_show[level])] self.logger.info(u'查看用户' + username + u'详细信息成功') return (True, detail_dict, show_list)
def parse(self, uuid_str): ''' 根据uuid_str读取callback日志 ''' log_prefix = '查询uuid为' + uuid_str + '的ansible任务执行报表' result = self.log_router.read(condition_dict={'uuid': uuid_str}, log_dict=self.log_dict, limit=0, lastest_field=False) self.readlog_list = result[1] if not result[0]: self.logger.error(log_prefix + '失败,原因:' + result[1]) return (False, log_prefix + '失败,' + result[1]) try: name = self.readlog_list[0]['name'] exec_mode = self.readlog_list[0]['mode'] describe = self.readlog_list[0]['describe'] options = self.readlog_list[0]['options'] # create_time = self.readlog_list[0]['create_time'] create_date = self.readlog_list[0]['create_date'] inventory_content = self.readlog_list[0]['inventory_content'] create_ts = self.readlog_list[0]['add_time'] finish_ts = self.readlog_list[-1]['add_time'] except Exception as e: self.logger.error(log_prefix + '失败,原因:该任务还没有开始执行或者数据错误,' + str(e)) return (False, '该任务还没有开始执行或者数据错误') pattern = self.readlog_list[0].get('pattern', None) module_name = self.readlog_list[0].get('module_name', None) module_args = self.readlog_list[0].get('module_args', None) yaml_content = self.readlog_list[0].get('yaml_content', None) play = self.readlog_list[0].get('play', {}) task = self.readlog_list[0].get('task', {}) newlog_dict = { 'name': name, 'mode': exec_mode, 'describe': describe, 'create_time': timestamp2datetime(create_ts), 'create_date': create_date, 'options': options, 'uuid': uuid_str, 'inventory_content': inventory_content, 'end_time': timestamp2datetime(finish_ts), 'duration': round((finish_ts - create_ts), 3), } if exec_mode == 'adhoc': newlog_dict['pattern'] = pattern newlog_dict['module_name'] = module_name newlog_dict['module_args'] = module_args else: newlog_dict['yaml_content'] = yaml_content get_field_list = ['uuid', 'play_id', 'task_id'] result = self.mongoclient.group_by(self.collect, get_field_list) if not result[0]: self.logger.error(log_prefix + '失败,原因:该任务还没有开始执行或者数据错误,' + result[1]) return (False, '该任务还没有开始执行或者数据错误') tempplay_dict = {} for playid in result[1]: if playid['uuid'] == uuid_str: play_id = playid['play_id'] task_id = playid.get('task_id', '') if task_id == '': continue else: continue if play_id not in tempplay_dict: tempplay_dict[play_id] = [] taskid_list = tempplay_dict[play_id] taskid_list.append(task_id) taskid_list = tempplay_dict[play_id] taskid_list = list(set(taskid_list)) taskid_list = sorted(taskid_list) # 对taskid执行先后顺序排序 tempplay_dict[play_id] = taskid_list playid_dict = {} for play_id in sorted(tempplay_dict): playid_dict[play_id] = tempplay_dict[play_id] # 对play执行先后顺序排序 play_dict = {} # 下面这个循环用于:根据play_id获取下面所有的task_id,并获取的每个task_id的最后日志和执行结果信息 for playid, taskid_list in playid_dict.items(): play_dict[playid] = {} for taskid in taskid_list: task_list = [] for line in self.readlog_list: if line['play_id'] == playid and line.get('task_id', '') == taskid: summary = line.get('summary', {}) if not summary: task_list.append(line) last_log = task_list[-1] # 求这个任务执行的最后一条日志 play_dict[playid]['play'] = last_log.get('play', {}) play_dict[playid]['summary'] = summary task_dict = { 'task': last_log.get('task', {}), 'detail': last_log.get('detail', {}), } try: play_dict[playid]['task'][taskid] = task_dict except: play_dict[playid]['task'] = {} play_dict[playid]['task'][taskid] = task_dict if not play_dict or not isinstance(play_dict, dict): self.logger.error(log_prefix + '失败,原因:该任务还没有开始执行或者查询条件错误,' + result[1]) return (False, {'result': '该任务还没有开始执行或者查询条件错误'}) result_dict = {} for play_uuid, logline in play_dict.items(): result_dict[play_uuid] = {} summary = logline.get('summary', {}) task_dict = logline.get('task', {}) if 'tasks' not in result_dict[play_uuid]: result_dict[play_uuid]['tasks'] = {} play = logline.get('play', {}) pattern = play.get('name', {}) for task_id, line in task_dict.items(): task = line.get('task', {}) task_name = task.get('name', '') taskmodule = task.get('module', '') # task_args = task.get('args', {}) if exec_mode == 'playbook' and task_name not in result_dict[ play_uuid]['tasks']: result_dict[play_uuid]['tasks'][task_name] = {} new_task = { 'module': task['module'], } result_dict[play_uuid]['tasks'][task_name][ 'tasks'] = new_task detail = line.get('detail', {}) if not isinstance(detail, dict) or not detail: continue for host, value in detail.items(): end_ts = value['end_ts'] start_ts = value['start_ts'] duration = end_ts - start_ts duration = round(duration, 2) ''' if taskmodule == 'yum' and 'invocation' in value : # 在yum模块中,在没有使用循环的情况下,value也含有results的key results = [value] else : results = value.get('results', {}) if results : data_list = results else : data_list = [value] # data_list = [value] ''' data_list = [value] for data in data_list: from library.connecter.ansible.callback.module import Parse_Result parse_module = Parse_Result() if taskmodule == 'command': result = parse_module.command(data, task) elif taskmodule == 'yum': if 'invocation' in data: result = parse_module.yum(data, task) else: try: temp_dict = data['results'][0] del data['results'] data.update(temp_dict) result = parse_module.yum(data, task) except: self.logger.error(data) result = parse_module.common_module( data, task, {}) elif taskmodule == 'service' or taskmodule == 'systemd': result = parse_module.service(data, task) elif taskmodule == 'script': result = parse_module.script(data, task) elif taskmodule == 'cron': result = parse_module.cron(data, task) elif taskmodule == 'user': result = parse_module.user(data, task) elif taskmodule == 'copy': result = parse_module.copy(data, task) elif taskmodule == 'get_url': result = parse_module.get_url(data, task) elif taskmodule == 'raw': result = parse_module.command(data, task) else: result = parse_module.common_module(data, task, {}) if taskmodule == '': print(result) if exec_mode == 'playbook': try: del result['模块名'] except: pass if 'detail' not in result_dict[play_uuid]['tasks'][ task_name]: result_dict[play_uuid]['tasks'][task_name][ 'detail'] = {} result_dict[play_uuid]['tasks'][task_name][ 'detail'][host] = result result_dict[play_uuid]['pattern'] = pattern else: try: del result['模块名'] del result_dict[play_uuid] except: pass result_dict[host] = result if exec_mode == 'playbook': result_dict[play_uuid]['summary'] = {} if isinstance(summary, dict): for host in summary: ok = summary[host].get('ok', 0) failures = summary[host].get('failures', 0) unreachable = summary[host].get('unreachable', 0) changed = summary[host].get('changed', 0) skipped = summary[host].get('skipped', 0) if ok == 0: if unreachable == 1: summary_str = '该任务在该主机上执行失败,无法连接远程主机' else: summary_str = '该任务在该主机上执行失败,失败数为' + str( failures) + ',跳过数为' + str( skipped) + ',可能产生变化数为' + str(changed) else: summary_str = '该任务在该主机上执行部分或者全部成功,成功数为' + str( ok) + ',失败数为' + str(failures) + ',跳过数为' + str( skipped) + ',可能产生变化数为' + str(changed) ''' result_dict[play_uuid]['summary'][host] = summary[host] 原文输出 ''' result_dict[play_uuid]['summary'][host] = summary_str if not result_dict[play_uuid]['summary']: result_dict[play_uuid]['summary'] = '该任务还没有执行完成' newlog_dict['exec_result'] = result_dict self.logger.info(log_prefix + '成功') return (True, newlog_dict)
def detail(self, username): ''' 查看用户详细信息 ''' old_user_dict = self.get_userinfo(username=username) if not old_user_dict : self.logger.error('查看用户' + username + '详细信息失败,原因:用户不存在') return (False, '用户' + username + '不存在') result = self.mongoclient.find(self.userinfo_mongocollect, condition_dict={'username':username}) if not result[0] : self.logger.error('查看用户' + username + '详细信息失败,原因:' + str(result[1])) return (False, '查询用户失败,' + str(result[1])) detail_mess = result[1][0] if detail_mess['isalive'] : isalive = '是' else : isalive = '否' if 'create_time' in detail_mess: create_date = timestamp2datetime(detail_mess['create_time']) else: create_date = timestamp2datetime(detail_mess['add_time']) if 'lastlogin_time' in detail_mess : lastlogin_time = timestamp2datetime(detail_mess['lastlogin_time']) else : lastlogin_time = '-' if 'lastedit_time' in detail_mess : lastedit_time = timestamp2datetime(detail_mess['lastedit_time']) else : lastedit_time = '-' if 'creater' in detail_mess : creater = detail_mess['creater'] else : creater = '-' if 'lastediter' in detail_mess : lastediter = detail_mess['lastediter'] else : lastediter = '-' detail_dict = { '真实姓名' : detail_mess['name'], '联系方式' : detail_mess['contact'], '是否激活' : isalive, '创建者' : creater, '创建时间' : create_date, '上次登录时间' : lastlogin_time, '上次编辑用户' : lastediter, '上次编辑时间' : lastedit_time, '是否激活' : isalive, } self.logger.info('查看用户' + username + '详细信息成功') return (True, detail_dict)
'%(asctime)s %(pathname)s:%(lineno)d %(module)s:%(funcName)s %(levelname)s %(message)s' }, # 日志格式 'min': { 'format': '%(asctime)s %(levelname)s %(message)s' } # 日志格式 }, 'filters': {}, 'handlers': { 'default': { 'level': 'INFO', # 允许保存日志的最低级别 'class': 'logging.handlers.RotatingFileHandler', # 'class':'logging.handlers.TimedRotatingFileHandler', 'filename': BASE_DIR + '/logs/lykops-' + timestamp2datetime(fmt='%Y-%m-%d') + '.log', # 日志输出文件 'formatter': 'standard', # 使用哪种formatters日志格式 }, 'weboper': { 'level': 'INFO', 'class': 'logging.handlers.RotatingFileHandler', # 'class':'logging.handlers.TimedRotatingFileHandler', 'filename': BASE_DIR + '/logs/weboper-' + timestamp2datetime(fmt='%Y-%m-%d') + '.log', # 日志输出文件 'formatter': 'standard', # 使用哪种formatters日志格式