def send_status(src, task_id, msg='', status=1, init=False, f_type=None, center_level=0): data = {"msg": msg, "task_id": task_id, 'src': src, 'status': status} cached_key = 'system:node_upgrade:task_{}'.format(task_id) # if status is None: # data['status'] = 1 # else: # data['status'] = status self = Node.objects.get(role='self') if init and src == self.uuid: all_step = 7 + center_level if f_type == 'system': # 系统更新 all_step += 5 else: # 功能组件更新 all_step += 2 data['all_step'] = all_step data['now_step'] = 0 cache.delete(cached_key) cache.set(cached_key, data) else: if data['status'] == 0: data['status'] = 1 cache_data = cache.get(cached_key, {}) cache_data.update(data) cache_data['now_step'] = cache_data.get('now_step', 0) + 1 progress = round( cache_data.get('now_step') / float(cache_data.get('all_step')), 2) * 100 cache_data['progress'] = int(progress) if src == self.uuid: cache.set(cached_key, cache_data) # 更新数据库 update_db(cache_data) else: parent = Node.objects.get(role='parent') if parent.api_url: url = parent.api_url else: url = "http://{}".format(parent.ip) api = NodeApi(base_url=url, secret_id=parent.secret_id, secret_key=parent.secret_key) api.request('/api/system/upgrade/progress', params=data) logger.error(json.dumps(cache_data, encoding="UTF-8", ensure_ascii=False))
def process_request(cls, request): """ 通过查询前端传递的参数中是否为调用子节点 直接在中间件中调用子节点API并返回数据 """ if request.method == "GET": data = request.GET elif request.method == "POST": data = request.POST else: return sub_id = data.get('node_parent_id') # 跨级子中心对应的上级中心 ID node_uuid = data.get('node_uuid') # 所属中心的uuid # 无对应参数,pass该请求 if not node_uuid: return agent = request.user.userinfo.agent try: sub_id = int(sub_id) except (TypeError, ValueError): sub_id = 0 try: node_obj = models.Node.objects.get(uuid=node_uuid) role = node_obj.role except models.Node.DoesNotExist: node_obj = None role = None # 如果为当前中心 pass if role == 'self': return # 如果为当前中心的下级 if node_obj: data = data.copy() data.pop("node_uuid") # 如果为当前中心的下下级 else: try: node_obj = models.Node.objects.get(id=sub_id, agent=agent) except models.Node.DoesNotExist: return JsonResponse({ "status": 500, "msg": "该中心不存在", "error": "该三级中心不存在" }) data = data.copy() data.pop("node_parent_id") node_api = NodeApi(base_url='http://{}:{}'.format( node_obj.ip, node_obj.port), secret_id=node_obj.secret_id, secret_key=node_obj.secret_key) result = node_api.fetch(method=request.method, api=request.path, params=data) return JsonResponse(result)
def upgrade_child(child_center, bin_file, targets, src, task_id, f_type): """升级下级""" bin_file = get_real_path(bin_file) for target in targets: if not target.get("id"): target['id'] = target.get("device_id") logger.error("start upgrade_child, child_center: {}".format( child_center.name)) data = { "src": src, "type": f_type, "targets": targets, "task_id": task_id, } if child_center.api_url: url = child_center.api_url else: url = "http://{}".format(child_center.ip) api = NodeApi(base_url=url, secret_id=child_center.secret_id, secret_key=child_center.secret_key) files = {'upgrade_file': open(bin_file, 'rb')} send_status(src, task_id, msg='向下发送更新包') logger.error("start upgrade_child, child_center: {} 向下发送更新包".format( child_center.name)) req = api.request('/api/system/upgrade/file/upload', files=files, headers={}) # os.remove(bin_file) if req.get("status") != 200: error = json.dumps(req, encoding="UTF-8", ensure_ascii=False) send_status(src, task_id, status=3, msg='向下发送更新包失败') logger.error( "start upgrade_child, child_center: {} 向下发送更新包失败, errors: {}". format(child_center.name, error)) return False send_status(src, task_id, msg='向下发送更新指令') logger.error("start upgrade_child, child_center: {} 向下发送更新指令".format( child_center.name)) logger.debug(req) data['file_id'] = req['data']['file_id'] data['u_type'] = req['data']['u_type'] req = api.request('/api/system/upgrade', params=data) if req.get("status") != 200: error = json.dumps(req, encoding="UTF-8", ensure_ascii=False) params = json.dumps(data, encoding="UTF-8", ensure_ascii=False) send_status(src, task_id, status=3, msg='向下发送更新指令失败') logger.error( "start upgrade_child, child_center: {} 向下发送更新指令失败, 参数: {} error: {}" .format(child_center.name, params, error))
def get_node_detailed_status(node): """ 获取中心状态 :param node: node_obj :return: """ if not node.secret_id or not node.secret_key: return {}, (500, '中心配置错误') node_api = NodeApi(base_url='http://' + node.ip, secret_id=node.secret_id, secret_key=node.secret_key) data, msg = node_api.get_detailed_status() return data, msg
def get_node_status(node): """ 获取中心状态 :param node: node_obj :return: """ if not node.secret_id or not node.secret_key: return 0, '中心配置错误' node_api = NodeApi(base_url='http://' + node.ip, secret_id=node.secret_id, secret_key=node.secret_key) status, msg = node_api.get_status() return status, msg
def check_parent_heartbeat(self, node): """ 查看上级中心的状态,以及角色变化 :param node: :return: """ self_node = models.Node.objects.filter(agent=node.agent, role='self').first() if not self_node: return False # 使用本中心的 key 作为认证 node_api = NodeApi(base_url='http://' + node.ip, auth_key=self_node.auth_key) data, msg = node_api.get_parent_status() return data
def delete(self, request, node_id): """ 删除中心信息 :param request: :param node_id: :return: """ node = self.get_object(request, node_id) if not node: context = { "status": 500, "msg": "获取中心错误", "error": "获取中心错误", } return Response(context) if node.role == "self": context = { "status": 500, "msg": "中心删除错误", "error": "中心删除错误", } return Response(context) node.delete() agent_now = request.user.userinfo.agent self_node = models.Node.objects.filter(agent=agent_now, role='self').last() if node.role == 'child': node_api = NodeApi( base_url='http://' + node.ip, secret_id=node.secret_id, secret_key=node.secret_key) params = json.dumps({'node_type': 'parent'}) status = node_api.clear_node(params) if status == 200: context = { "status": 200, "msg": "删除中心成功", } else: context = { "status": 500, "msg": "删除错误", } else: context = { "status": 500, "msg": "删除错误", } return Response(context)
def get_node_api(self, node): """ api :param node: :return: """ api = NodeApi(base_url='http://' + node.ip, secret_id=node.secret_id, secret_key=node.secret_key) return api
def fetch_node_topo(self, node): """ 获取中心 topo :param node: :return: """ node_api = NodeApi(base_url='http://' + node.ip, secret_id=node.secret_id, secret_key=node.secret_key) topo = node_api.get_topo() if topo.get('role') == 'parent': topo = topo.get("children") if len(topo) == 1: topo = topo[0].get("children", []) else: topo = [] elif topo.get('role') == 'self': topo = topo.get("children", []) else: topo = [] return topo
def delete(self, request): """清除上下级级联关系""" node_type = request.DATA.get('node_type') msg = '' agent = request.user.userinfo.agent self_node = models.Node.objects.filter(agent=agent, role='self').last() if node_type == 'parent': parents = models.Node.objects.filter(agent=agent, role='parent') for pa in parents: node_api = NodeApi( base_url='http://' + pa.ip, auth_key=self_node.auth_key) status = node_api.clear_node_parent() if status == 200: pa.delete() msg = '上级中心解除成功' elif node_type == 'children': children = models.Node.objects.filter(agent=request.user.userinfo.agent, role='child') for chi in children: node_api = NodeApi( base_url='http://' + chi.ip, secret_id=chi.secret_id, secret_key=chi.secret_key) params = json.dumps({'node_type': 'parent'}) status = node_api.clear_node(params) if status == 200: chi.delete() msg = '下级中心解除成功' return Response({ "status": 200, "msg": msg, })
def post(self, request): """ 调用子中心API接口 """ api = request.data.get("api") node_uuid = request.data.get("uuid") params = request.data.get("params") method = request.data.get("method") agent = request.user.userinfo.agent try: node_obj = models.Node.objects.get(uuid=node_uuid, agent=agent) except models.Node.DoesNotExist: return Response({"status": 500, "msg": "该中心不存在", "error": "该中心不存在"}) node_api = NodeApi(base_url='http://{}:{}'.format(node_obj.ip, node_obj.port), secret_id=node_obj.secret_id, secret_key=node_obj.secret_key) try: params = json.loads(params) except (TypeError, ValueError): params = None result = node_api.fetch(method=method, api=api, params=params) return Response(result)
def get(self, request): """ 级联树状拓扑 """ try: # 级联树从当前中心开下 node_tree = models.Node.objects.get(role="self").get_dict() except models.Node.DoesNotExist: node_tree = {"name": "本中心"} del node_tree['auth_key'] # 当前中心为二级中心 从数据库获取三级中心 if node_tree['type'] == "sub_center": childrens = models.Node.objects.filter(agent=request.user.userinfo.agent, role='child') children_list = [] for children in childrens: children_dict = children.get_dict() del children_dict['auth_key'] children_list.append(children.get_dict()) node_tree['children'] = children_list # 当前中心为一级中心, 从数据库获取二级中心,从API接口获取三级中心 if node_tree['type'] == "center": childrens = models.Node.objects.filter(agent=request.user.userinfo.agent, role='child') children_list = [] for children in childrens: children_dict = children.get_dict() del children_dict['auth_key'] if children.type == "sub_center": node_api = NodeApi(base_url='http://{}:{}'.format(children.ip, children.port), secret_id=children.secret_id, secret_key=children.secret_key) result = node_api.fetch(method="get", api=request.path) status = result['status'] if status == 200: children_dict['children'] = result['data']['children'] children_list.append(children_dict) node_tree['children'] = children_list return Response({"status": 200, "data": node_tree})
def get(self, request): """ 获取当前中心信息 :param request: :return: """ self_node = self.get_object(request) if self_node: data = self_node.get_dict() else: data = { "accept_parent_connection": 0, "accept_apply_policy": 0, "accept_apply_event_db": 0, "accept_apply_engine": 0, "accept_apply_center": 0, "ip": "127.0.0.1", "role": "self", "name": "127.0.0.1", } status_code = 200 # 处理 API 请求 if request.is_api: node_api = NodeApi(base_url="http://127.0.0.1:80", auth_key=self_node.auth_key) # todo 判断级联状态 # 401: "下级中心不允许级联管理", # 403: "中心版本需要升级", # 404: "上级中心未添加级联", if data["accept_parent_connection"] == 0: status_code = 401 return Response({ "status": status_code, "msg": "下级中心不允许级联", "error": "下级中心不允许级联" }) context = { "status": status_code, "msg": "获取成功", "data": data } return Response(context)
def send_heartbeat(self, node): """ 心跳检测 :param node: obj :return: """ if not node.auth_key: # 没有配置级联秘钥 node.status = 2 node.save() self.update_next_check_time(node) self.send_node_alert(node, "级联秘钥错误") return False if not node.secret_key or not node.secret_id: # fetch secret_key and secret_id node_api = NodeApi(base_url='http://' + node.ip, auth_key=node.auth_key) result = node_api.fetch_auth(self_node_info=node.get_dict()) if result["status"] == 200: node.secret_id = result["data"]["secret_id"] node.secret_key = result["data"]["secret_key"] node.save() else: # 级联秘钥获取 token 错误 node.status = 2 node.save() self.update_next_check_time(node) self.send_node_alert(node, "级联秘钥错误") return False # check status node_api = NodeApi(base_url='http://' + node.ip, secret_id=node.secret_id, secret_key=node.secret_key) data, msg = node_api.get_detailed_status() if not data: node.status = 2 node.save() self.send_node_alert(node, msg[1]) return False # 更新状态和信息 node.status = 1 node.last_heartbeat = timezone.now() node.type = data['type'] node.save() self.update_next_check_time(node) return True