def nodeman_get_plugin_version(request, plugin, os_type): """根据系统获取插件版本""" client = BKNodeManClient(username=request.user.username) kwargs = {"name": plugin, "os": os_type.upper()} plugin_version_list = client.plugin_package(**kwargs) if not plugin_version_list["result"]: message = handle_api_error(_("节点管理(NODEMAN)"), "nodeman.plugin_package", {}, plugin_version_list) logger.error(message) return JsonResponse({ "result": plugin_version_list["result"], "code": plugin_version_list.get("code", "-1"), "message": message }) data = plugin_version_list["data"] result = [{ "text": version["version"], "value": version["version"] } for version in data] plugin_version_list["data"] = result return JsonResponse(plugin_version_list)
def get_host_id_by_inner_ip(executor, logger, bk_cloud_id: int, bk_biz_id: int, ip_list: list): """ 根据inner_ip获取bk_host_id 对应关系dict """ client = BKNodeManClient(username=executor) kwargs = { "bk_biz_id": [bk_biz_id], "pagesize": -1, "conditions": [{ "key": "inner_ip", "value": ip_list }, { "key": "bk_cloud_id", "value": [bk_cloud_id] }], } result = client.search_host_plugin(**kwargs) if not result["result"]: error = handle_api_error(__group_name__, "nodeman.search_host_plugin", kwargs, result) logger.error(error) return {} return { host["inner_ip"]: host["bk_host_id"] for host in result["data"]["list"] }
def execute(self, data, parent_data): executor = parent_data.inputs.executor client = BKNodeManClient(username=executor) bk_biz_id = data.inputs.biz_cc_id nodeman_op_target = data.inputs.nodeman_plugin_operate op_type = nodeman_op_target.get("nodeman_op_type", "") plugin = nodeman_op_target.get("nodeman_plugin", "") plugin_version = nodeman_op_target.get("nodeman_plugin_version", "") install_config = nodeman_op_target.get("install_config", []) host_info = data.inputs.nodeman_host_info input_type = host_info.get("nodeman_host_input_type", None) if not input_type: data.set_outputs("ex_data", _("请选择填写方式")) return False if input_type == "host_ip": bk_cloud_id = host_info.get("nodeman_bk_cloud_id", None) ip_list = get_ip_by_regex(host_info.get("nodeman_host_ip", "")) host_id_dict = get_host_id_by_inner_ip(executor, self.logger, bk_cloud_id, bk_biz_id, ip_list) # 过滤出未查询到host_id的ip no_host_id_ip = list(set(ip_list).difference(set(host_id_dict.keys()))) if no_host_id_ip: data.set_outputs("ex_data", _("获取bk_host_id失败:{},请确认云区域是否正确".format(",".join(no_host_id_ip)))) return False host = list(host_id_dict.values()) else: host = host_info.get("nodeman_host_id", "").strip().split(",") # 拼装参数 params = { "job_type": op_type, "bk_biz_id": [bk_biz_id], "bk_host_id": host, "plugin_params": {"name": plugin}, } if plugin_version: params["plugin_params"]["version"] = plugin_version if op_type == "MAIN_INSTALL_PLUGIN" and install_config: if "keep_config" in install_config: params["plugin_params"].update({"keep_config": 1}) elif "no_restart" in install_config: params["plugin_params"].update({"no_restart": 1}) result = client.plugin_operate(params) job_is_plugin = True if result["result"]: # 这里兼容节点管理新老接口 if plugin not in result["data"]: job_is_plugin = False job_id = result["data"].get(plugin, None) or result["data"].get("job_id", None) data.outputs.job_url = [get_nodeman_job_url(job_id, host_id) for host_id in host] return self.get_job_result(result, data, "plugin_operate", params, job_is_plugin=job_is_plugin)
def get_nodeman_rsa_public_key(executor, logger): """ 拉取节点管理rsa公钥 """ client = BKNodeManClient(username=executor) get_rsa_result = client.get_rsa_public_key(executor) if not get_rsa_result["result"]: error = handle_api_error(__group_name__, "nodeman.get_rsa_public_key", executor, get_rsa_result) logger.error(error) return False, None content = get_rsa_result["data"][0]["content"] name = get_rsa_result["data"][0]["name"] return True, {"name": name, "content": content}
def nodeman_get_ap_list(request): client = BKNodeManClient(username=request.user.username) ap_list = client.ap_list() if not ap_list["result"]: message = handle_api_error(_("节点管理(NODEMAN)"), "nodeman.ap_list", {}, ap_list) logger.error(message) return JsonResponse({ "result": ap_list["result"], "code": ap_list.get("code", "-1"), "message": message }) data = ap_list["data"] result = [{"text": ap["name"], "value": ap["id"]} for ap in data] ap_list["data"] = result return JsonResponse(ap_list)
def nodeman_get_plugin_list(request, category): """获取插件列表""" client = BKNodeManClient(username=request.user.username) plugin_list = client.plugin_process(category) if not plugin_list["result"]: message = handle_api_error(_("节点管理(NODEMAN)"), "nodeman.plugin_process", {}, plugin_list) logger.error(message) return JsonResponse({ "result": plugin_list["result"], "code": plugin_list.get("code", "-1"), "message": message }) data = plugin_list["data"] result = [{"text": ap["name"], "value": ap["name"]} for ap in data] plugin_list["data"] = result return JsonResponse(plugin_list)
def nodeman_get_cloud_area(request): client = BKNodeManClient(username=request.user.username) cloud_area_result = client.cloud_list() if not cloud_area_result["result"]: message = handle_api_error(_("节点管理(NODEMAN)"), "nodeman.cloud_list", {}, cloud_area_result) logger.error(message) return JsonResponse({ "result": cloud_area_result["result"], "code": cloud_area_result.get("code", "-1"), "message": message }) data = cloud_area_result["data"] result = [{ "text": cloud["bk_cloud_name"], "value": cloud["bk_cloud_id"] } for cloud in data] cloud_area_result["data"] = result return JsonResponse(cloud_area_result)
def execute(self, data, parent_data): executor = parent_data.inputs.executor client = BKNodeManClient(username=executor) bk_biz_id = data.inputs.bk_biz_id nodeman_op_target = data.inputs.nodeman_op_target bk_cloud_id = nodeman_op_target.get("nodeman_bk_cloud_id", "") node_type = nodeman_op_target.get("nodeman_node_type", "") nodeman_ticket = data.get_one_of_inputs("nodeman_ticket", {}) nodeman_tjj_ticket = nodeman_ticket.get("nodeman_tjj_ticket", "") if nodeman_tjj_ticket: try: nodeman_tjj_ticket = decrypt_auth_key(nodeman_tjj_ticket, settings.RSA_PRIV_KEY) except Exception: # password is not encrypted pass nodeman_op_info = data.inputs.nodeman_op_info op_type = nodeman_op_info.get("nodeman_op_type", "") nodeman_hosts = nodeman_op_info.get("nodeman_hosts", []) ap_id = nodeman_op_info.get("nodeman_ap_id", "") ip_str = nodeman_op_info.get("nodeman_ip_str", "") data.set_outputs("job_id", "") # 拼接任务类型 job_name = "_".join([op_type, node_type]) if job_name in itertools.chain.from_iterable([OPERATE_JOB, REMOVE_JOB]): # 获取bk_host_id ip_list = get_ip_by_regex(ip_str) bk_host_id_dict = get_host_id_by_inner_ip(executor, self.logger, bk_cloud_id, bk_biz_id, ip_list) bk_host_ids = [bk_host_id for bk_host_id in bk_host_id_dict.values()] # 操作类任务(升级、卸载等) if job_name in OPERATE_JOB: kwargs = { "job_type": job_name, "bk_biz_id": [bk_biz_id], "bk_host_id": bk_host_ids, "action": "job_operate", } # 移除主机 elif job_name in REMOVE_JOB: kwargs = { "bk_biz_id": [bk_biz_id], "bk_host_id": bk_host_ids, "is_proxy": True if "PROXY" in job_name else False, # 是否移除PROXY "action": "remove_host", } else: return False # 安装类任务 elif job_name in INSTALL_JOB: # 安装主机信息 all_hosts, row_host_params_list = [], [] for host in nodeman_hosts: auth_type = host["auth_type"] auth_key = host["auth_key"] inner_ip_list = get_ip_by_regex(host.get("inner_ip")) if not inner_ip_list: data.set_outputs("ex_data", _("请确认内网Ip是否合法host_info:{host}".format(host=host["inner_ip"]))) return False # 处理表格中每行的key/psw try: auth_key = decrypt_auth_key(auth_key, settings.RSA_PRIV_KEY) except Exception: # password is not encrypted pass # auth_key加密 success, ras_public_key = get_nodeman_rsa_public_key(executor, self.logger) if not success: data.set_outputs("ex_data", _("获取节点管理公钥失败,请查看节点日志获取错误详情.")) return False auth_key = encrypt_auth_key(auth_key, ras_public_key["name"], ras_public_key["content"]) # 表格每行基础参数 base_params = { "bk_biz_id": bk_biz_id, "bk_cloud_id": bk_cloud_id, "os_type": host["os_type"], "port": host["port"], "account": host["account"], "auth_type": auth_type, "ap_id": ap_id, "is_manual": False, # 不手动操作 "peer_exchange_switch_for_agent": 0, # 不加速 } # 支持表格中一行多ip操作, 拼装表格内的inner_ip参数 for index, inner_ip in enumerate(inner_ip_list): one = {"inner_ip": inner_ip} if auth_type == "PASSWORD": one["password"] = auth_key else: one["key"] = auth_key # 重装必须要bk_host_id if job_name in ["REINSTALL_PROXY", "REINSTALL_AGENT"]: bk_host_id_dict = get_host_id_by_inner_ip( executor, self.logger, bk_cloud_id, bk_biz_id, inner_ip_list ) try: one["bk_host_id"] = bk_host_id_dict[inner_ip] except KeyError: data.set_outputs("ex_data", _("获取bk_host_id失败:{},请确认云区域是否正确".format(inner_ip))) return False # 组装其它可选参数, ip数量需要与inner_ip一一对应 for ip_type in HOST_EXTRA_PARAMS: if host.get(ip_type, False): others_ip_list = get_ip_by_regex(host[ip_type]) if len(others_ip_list) == len(inner_ip_list): one[ip_type] = others_ip_list[index] else: data.set_outputs("ex_data", _("获取{}的{}失败,请确认是否与inner_ip一一对应".format(inner_ip, ip_type))) return False one.update(base_params) row_host_params_list.append(one) all_hosts.extend(row_host_params_list) kwargs = {"job_type": job_name, "hosts": all_hosts, "action": "job_install"} if nodeman_tjj_ticket: kwargs.update({"tcoa_ticket": nodeman_tjj_ticket}) else: data.set_outputs("ex_data", _("无效的操作请求:{}".format(job_name))) return False action = kwargs.pop("action") result = getattr(client, action)(**kwargs) return self.get_job_result(result, data, action, kwargs)
def schedule(self, data, parent_data, callback_data=None): executor = parent_data.inputs.executor client = BKNodeManClient(username=executor) job_id = data.get_one_of_outputs("job_id", "") if not job_id: self.finish_schedule() return True job_kwargs = {"job_id": job_id} job_result = client.job_details(**job_kwargs) # 获取执行结果 if not self.get_job_result(job_result, data, "nodeman.job_details", job_kwargs, set_output_job_id=False): self.finish_schedule() return False result_data = job_result["data"] job_statistics = result_data["statistics"] success_num = job_statistics["success_count"] fail_num = job_statistics["failed_count"] host_list = result_data["list"] data.set_outputs("success_num", success_num) data.set_outputs("fail_num", fail_num) if result_data["status"] == "SUCCESS": self.finish_schedule() return True # 失败任务信息 if result_data["status"] in ["FAILED", "PART_FAILED"]: fail_infos = [{ "inner_ip": host["inner_ip"], "instance_id": host["instance_id"] } for host in host_list if host["status"] == "FAILED"] # 查询失败任务日志 error_log = "<br>{mes}</br>".format(mes=_("操作失败主机日志信息:")) for fail_info in fail_infos: log_kwargs = { "job_id": job_id, "instance_id": fail_info["instance_id"], } result = client.get_job_log(**log_kwargs) if not result["result"]: result["message"] += json.dumps(result["data"], ensure_ascii=False) error = handle_api_error(__group_name__, "nodeman.get_job_log", log_kwargs, result) data.set_outputs("ex_data", error) self.finish_schedule() return False # 提取出错步骤日志 log_info = [ _log for _log in result["data"] if _log["status"] == "FAILED" ] error_log = "{error_log}<br><b>{host}{fail_host}</b></br><br>{log}</br>{log_info}".format( error_log=error_log, host=_("主机:"), fail_host=fail_info["inner_ip"], log=_("错误日志:"), log_info="{}\n{}".format(log_info[0]["step"], log_info[0]["log"]), ) data.set_outputs("ex_data", error_log) self.finish_schedule() return False
def execute(self, data, parent_data): executor = parent_data.inputs.executor client = BKNodeManClient(username=executor) bk_biz_id = data.inputs.biz_cc_id bk_cloud_id = data.inputs.nodeman_bk_cloud_id node_type = data.inputs.nodeman_node_type op_type = data.inputs.nodeman_op_type nodeman_hosts = data.inputs.nodeman_hosts hosts = [] for host in nodeman_hosts: conn_ips = get_ip_by_regex(host["conn_ips"]) if len(conn_ips) == 0: data.set_outputs("ex_data", _("conn_ips 为空或输入格式错误")) return False one = { "os_type": host["os_type"], "has_cygwin": host["has_cygwin"], "port": host["port"], "account": host["account"], "auth_type": host["auth_type"], } auth_type = host["auth_type"] auth_key = host["auth_key"] login_ip = get_ip_by_regex(host.get("login_ip", "")) data_ip = get_ip_by_regex(host.get("data_ip", "")) cascade_ip = get_ip_by_regex(host.get("cascade_ip", "")) if login_ip: one.update({"login_ip": login_ip[0]}) if data_ip: one.update({"data_ip": data_ip[0]}) if cascade_ip: one.update({"cascade_ip": cascade_ip[0]}) # 处理key/psw try: auth_key = rsa_decrypt_password(auth_key, settings.RSA_PRIV_KEY) except Exception: # password is not encrypted pass auth_key = nodeman_rsa_encrypt(auth_key).decode("utf-8") one.update({auth_type.lower(): auth_key}) for conn_ip in conn_ips: dict_temp = {"conn_ips": conn_ip} dict_temp.update(one) hosts.append(dict_temp) agent_kwargs = { "bk_biz_id": bk_biz_id, "bk_cloud_id": bk_cloud_id, "node_type": node_type, "op_type": op_type, "creator": executor, "hosts": hosts, } agent_result = client.create_task(**agent_kwargs) self.logger.info( "nodeman created task result: {result}, api_kwargs: {kwargs}". format(result=agent_result, kwargs=agent_kwargs)) if agent_result["result"]: data.set_outputs("job_id", agent_result["data"]["id"]) return True else: message = "create agent install task failed: %s" % agent_result[ "message"] data.set_outputs("ex_data", message) return False
def schedule(self, data, parent_data, callback_data=None): bk_biz_id = data.inputs.biz_cc_id executor = parent_data.inputs.executor client = BKNodeManClient(username=executor) job_id = data.get_one_of_outputs("job_id") job_kwargs = {"bk_biz_id": bk_biz_id, "job_id": job_id} job_result = client.get_task_info(**job_kwargs) self.logger.info( "nodeman get task info result: {result}, api_kwargs: {kwargs}". format(result=job_result, kwargs=job_kwargs)) # 任务执行失败 if not job_result["result"]: self.logger.error( "nodeman get task info result: {result}, api_kwargs: {kwargs}". format(result=job_result, kwargs=job_kwargs)) data.set_outputs("ex_data", _("查询失败,未能获得任务执行结果")) self.finish_schedule() return False result_data = job_result["data"] host_count = result_data["host_count"] success_num = result_data["status_count"]["success_count"] fail_num = result_data["status_count"]["failed_count"] fail_infos = [] for host in result_data["hosts"]: # 安装失败 if host["status"] == "FAILED": fail_infos.append({ "host_id": host["host"]["id"], "inner_ip": host["host"]["inner_ip"] }) if success_num + fail_num == host_count: data.set_outputs("success_num", success_num) data.set_outputs("fail_num", fail_num) if success_num == host_count: self.finish_schedule() return True else: error_log = "<br>%s</br>" % _("日志信息为:") for fail_info in fail_infos: log_kwargs = { "host_id": fail_info["host_id"], "bk_biz_id": bk_biz_id, } result = client.get_log(**log_kwargs) log_info = result["data"]["logs"] error_log = "{error_log}<br><b>{host}{fail_host}</b></br><br>{log}</br>{log_info}".format( error_log=error_log, host=_("主机:"), fail_host=fail_info["inner_ip"], log=_("日志:"), log_info=log_info, ) data.set_outputs("ex_data", error_log) self.finish_schedule() return False