def get_task_detail(request, task_id, project_id): """ @summary: 获取任务详细信息 @param request: @param task_id: @param project_id: @return: """ project = request.project try: task = TaskFlowInstance.objects.get(id=task_id, project_id=project.id) except TaskFlowInstance.DoesNotExist: message = ( "[API] get_task_detail task[id={task_id}] " "of project[project_id={project_id}, biz_id{biz_id}] does not exist" .format(task_id=task_id, project_id=project.id, biz_id=project.bk_biz_id)) logger.exception(message) return { "result": False, "message": message, "code": err_code.CONTENT_NOT_EXIST.code } data = task.get_task_detail() return {"result": True, "data": data, "code": err_code.SUCCESS.code}
def get_user_project_detail(request, project_id): try: biz_detail = get_business_detail(request.user.username, request.project.bk_biz_id) except Exception as e: logger.exception( "[API] get_user_business_detail call fail: {}".format(e)) return { "result": False, "message": "can not get business[{}] detail for user[{}]".format( request.user.username, request.project.bk_biz_id), "code": err_code.UNKNOWN_ERROR.code, } return { "result": True, "data": { "project_id": request.project.id, "project_name": request.project.name, "from_cmdb": request.project.from_cmdb, "bk_biz_id": biz_detail["bk_biz_id"], "bk_biz_name": biz_detail["bk_biz_name"], "bk_biz_developer": biz_detail["bk_biz_developer"], "bk_biz_maintainer": biz_detail["bk_biz_maintainer"], "bk_biz_tester": biz_detail["bk_biz_tester"], "bk_biz_productor": biz_detail["bk_biz_productor"], }, "code": err_code.SUCCESS.code, }
def node_callback(request, task_id, project_id): try: params = json.loads(request.body) except Exception: return { "result": False, "message": "invalid json format", "code": err_code.REQUEST_PARAM_INVALID.code } project = request.project try: task = TaskFlowInstance.objects.get(id=task_id, project_id=project.id) except TaskFlowInstance.DoesNotExist: message = ( "[API] node_callback task[id={task_id}] " "of project[project_id={project_id}, biz_id{biz_id}] does not exist" .format(task_id=task_id, project_id=project.id, biz_id=project.bk_biz_id)) logger.exception(message) return { "result": False, "message": message, "code": err_code.CONTENT_NOT_EXIST.code } node_id = params.get("node_id") callback_data = params.get("callback_data") version = params.get("version") return task.callback(node_id, callback_data, version)
def preview_task_tree(request, project_id, template_id): try: req_data = json.loads(request.body) except Exception: return { "result": False, "message": "request body is not a valid json", "code": err_code.REQUEST_PARAM_INVALID.code, } version = req_data.get("version") exclude_task_nodes_id = req_data.get("exclude_task_nodes_id", []) if not isinstance(exclude_task_nodes_id, list): return { "result": False, "message": "invalid exclude_task_nodes_id", "code": err_code.REQUEST_PARAM_INVALID.code, } try: data = preview_template_tree(request.project.id, PROJECT, template_id, version, exclude_task_nodes_id) except Exception as e: logger.exception("[API] preview_task_tree fail: {}".format(e)) return { "result": False, "message": "preview_task_tree fail: {}".format(e), "code": err_code.UNKNOWN_ERROR.code } return {"result": True, "data": data, "code": err_code.SUCCESS.code}
def fast_create_task(request, project_id): params = request.params_json project = request.project logger.info( "[API] fast_create_task info, project_id: {project_id}, params: {params}".format( project_id=project.id, params=params ) ) try: pipeline_tree = params["pipeline_tree"] pipeline_instance_kwargs = { "name": standardize_name(params["name"], TASK_NAME_MAX_LENGTH), "creator": request.user.username, "pipeline_tree": pipeline_tree, "description": params.get("description", ""), } except (KeyError, ValueError) as e: return {"result": False, "message": "invalid params: %s" % str(e), "code": err_code.REQUEST_PARAM_INVALID.code} has_common_subprocess = params.get("has_common_subprocess", False) try: template = ( CommonTemplate(pipeline_template=None) if has_common_subprocess else TaskTemplate(pipeline_template=None) ) pipeline_instance = TaskFlowInstance.objects.create_pipeline_instance( template=template, **pipeline_instance_kwargs ) except PipelineException as e: message = "[API] fast_create_task create pipeline error: %s" % str(e) logger.exception(message) return {"result": False, "message": message, "code": err_code.UNKNOWN_ERROR.code} taskflow_kwargs = { "project": project, "pipeline_instance": pipeline_instance, "template_source": ONETIME, "create_method": "api", } if params.get("category") in [cate[0] for cate in TASK_CATEGORY]: taskflow_kwargs["category"] = params["category"] # 职能化任务,新建后进入职能化认领阶段 if params.get("flow_type", "common") == "common_func": taskflow_kwargs["flow_type"] = "common_func" taskflow_kwargs["current_flow"] = "func_claim" # 常规流程,新建后即可执行 else: taskflow_kwargs["flow_type"] = "common" taskflow_kwargs["current_flow"] = "execute_task" task = TaskFlowInstance.objects.create(**taskflow_kwargs) return { "result": True, "data": {"task_id": task.id, "task_url": task.url, "pipeline_tree": task.pipeline_tree}, "code": err_code.SUCCESS.code, }
def get_functionalization_task_list(request): id_in = request.GET.get("id_in") task_id_in = request.GET.get("task_id_in") status = request.GET.get("status") if id_in: try: id_in = id_in.split(",") except Exception: id_in = None logger.exception( "[API] get_functionalization_task_list id_in[{}] resolve fail, ignore." .format(id_in)) if task_id_in: try: task_id_in = task_id_in.split(",") except Exception: task_id_in = None logger.exception( "[API] get_functionalization_task_list task_id_in[{}] resolve fail, ignore." .format(task_id_in)) filter_kwargs = {} if status: filter_kwargs["status"] = status if id_in: filter_kwargs["id__in"] = id_in if task_id_in: filter_kwargs["task__id__in"] = task_id_in function_tasks = FunctionTask.objects.select_related("task").filter( **filter_kwargs) try: function_tasks, count = paginate_list_data(request, function_tasks) except Exception as e: return { "result": False, "data": "", "message": e, "code": err_code.INVALID_OPERATION.code } data = format_function_task_list_data(function_tasks) response = { "result": True, "data": data, "count": count, "code": err_code.SUCCESS.code } return response
def get_template_list(request, project_id): template_source = request.GET.get("template_source", PROJECT) id_in = request.GET.get("id_in", None) name_keyword = request.GET.get("name_keyword", None) if id_in: try: id_in = id_in.split(",") except Exception: id_in = None logger.exception( "[API] id_in[{}] resolve fail, ignore.".format(id_in)) filter_kwargs = dict(is_deleted=False) if id_in: filter_kwargs["id__in"] = id_in if name_keyword and name_keyword != "": filter_kwargs["pipeline_template__name__icontains"] = name_keyword project = request.project if template_source in NON_COMMON_TEMPLATE_TYPES: filter_kwargs["project_id"] = project.id templates = TaskTemplate.objects.select_related( "pipeline_template").filter(**filter_kwargs) else: templates = CommonTemplate.objects.select_related( "pipeline_template").filter(**filter_kwargs) template_list, template_id_list = format_template_list_data( templates, project, return_id_list=True) # 注入用户有权限的actions flow_allowed_actions = get_flow_allowed_actions_for_user( request.user.username, FLOW_ACTIONS, template_id_list) for template_info in template_list: template_id = template_info["id"] template_info.setdefault("auth_actions", []) for action, allowed in flow_allowed_actions.get(str(template_id), {}).items(): if allowed: template_info["auth_actions"].append(action) return { "result": True, "data": template_list, "code": err_code.SUCCESS.code }
def import_project_template(request, project_id): if not request.is_trust: return { "result": False, "message": "you have no permission to call this api.", "code": err_code.REQUEST_FORBIDDEN_INVALID.code, } try: req_data = json.loads(request.body) except Exception: return { "result": False, "message": "invalid json format", "code": err_code.REQUEST_PARAM_INVALID.code } template_data = req_data.get("template_data", None) if not template_data: return { "result": False, "message": "template data can not be none", "code": err_code.REQUEST_PARAM_INVALID.code, } r = read_encoded_template_data(template_data) if not r["result"]: return r try: import_result = TaskTemplate.objects.import_templates( template_data=r["data"]["template_data"], override=False, project_id=request.project.id, operator=request.user.username, ) except Exception as e: logger.exception("[API] import common tempalte error: {}".format(e)) return { "result": False, "message": "invalid flow data or error occur, please contact administrator", "code": err_code.UNKNOWN_ERROR.code, } return import_result
def get_task_node_detail(request, task_id, project_id): """ @summary: 获取节点输入输出 @param request: @param task_id: @param project_id: @return: """ project = request.project try: task = TaskFlowInstance.objects.get(id=task_id, project_id=project.id) except TaskFlowInstance.DoesNotExist: message = ( "[API] get_task_node_detail task[id={task_id}] " "of project[project_id={project_id}, biz_id{biz_id}] does not exist" .format(task_id=task_id, project_id=project.id, biz_id=project.bk_biz_id)) logger.exception(message) return { "result": False, "message": message, "code": err_code.CONTENT_NOT_EXIST.code } node_id = request.GET.get("node_id") component_code = request.GET.get("component_code") try: subprocess_stack = json.loads(request.GET.get("subprocess_stack", "[]")) except Exception: return { "result": False, "message": "subprocess_stack is not a valid array json", "code": err_code.UNKNOWN_ERROR.code, } result = task.get_node_detail( node_id=node_id, username=request.user.username, component_code=component_code, subprocess_stack=subprocess_stack, project_id=project_id, ) return result
def get_user_project_list(request): try: projects = get_user_projects(request.user.username) except Exception as e: logger.exception("[API] get_user_project_list call fail: {}".format(e)) return { "result": False, "message": "can not fetch project for user[{}]".format(request.user.username), "code": err_code.UNKNOWN_ERROR.code, } data = [{ "project_id": proj.id, "bk_biz_id": proj.bk_biz_id, "name": proj.name } for proj in projects if not proj.is_disable] return {"result": True, "data": data, "code": err_code.SUCCESS.code}
def claim_functionalization_task(request, task_id, project_id): try: params = json.loads(request.body) except Exception: return { "result": False, "message": "request body is not a valid json", "code": err_code.REQUEST_PARAM_INVALID.code, } constants = params.get("constants", {}) name = params.get("name", "") try: task = TaskFlowInstance.objects.get(pk=task_id, project_id=request.project.id) result = task.task_claim(request.user.username, constants, name) except Exception as e: logger.exception( "[API] claim_functionalization_task fail: {}".format(e)) return { "result": False, "message": "claim_functionalization_task fail: {}".format(e), "code": err_code.UNKNOWN_ERROR.code, } if result["result"] is False: return { "result": False, "message": result["message"], "code": err_code.UNKNOWN_ERROR.code } return { "result": True, "data": result["message"], "code": err_code.SUCCESS.code }
def create_task(request, template_id, project_id): params = json.loads(request.body) project = request.project template_source = params.get("template_source", PROJECT) logger.info( "[API] create_task info, template_id: {template_id}, project_id: {project_id}, params: {params}" .format(template_id=template_id, project_id=project.id, params=params)) # 兼容老版本的接口调用 if template_source in NON_COMMON_TEMPLATE_TYPES: template_source = PROJECT try: tmpl = TaskTemplate.objects.select_related( "pipeline_template").get(id=template_id, project_id=project.id, is_deleted=False) except TaskTemplate.DoesNotExist: result = { "result": False, "message": "template[id={template_id}] of project[project_id={project_id},biz_id={biz_id}] " "does not exist".format(template_id=template_id, project_id=project.id, biz_id=project.bk_biz_id), "code": err_code.CONTENT_NOT_EXIST.code, } return result else: try: tmpl = CommonTemplate.objects.select_related( "pipeline_template").get(id=template_id, is_deleted=False) except CommonTemplate.DoesNotExist: result = { "result": False, "message": "common template[id={template_id}] does not exist".format( template_id=template_id), "code": err_code.CONTENT_NOT_EXIST.code, } return result app_code = getattr(request.jwt.app, settings.APIGW_APP_CODE_KEY) if not app_code: message = "app_code cannot be empty, make sure api gateway has sent correct params" return { "result": False, "message": message, "code": err_code.CONTENT_NOT_EXIST.code } try: params.setdefault("flow_type", "common") params.setdefault("constants", {}) params.setdefault("exclude_task_nodes_id", []) params.setdefault("simplify_vars", []) params.setdefault("execute_task_nodes_id", []) jsonschema.validate(params, APIGW_CREATE_TASK_PARAMS) except jsonschema.ValidationError as e: logger.exception("[API] create_task raise prams error: %s" % e) message = "task params is invalid: %s" % e return { "result": False, "message": message, "code": err_code.REQUEST_PARAM_INVALID.code } create_with_tree = "pipeline_tree" in params pipeline_instance_kwargs = { "name": params["name"], "creator": request.user.username, "description": params.get("description", ""), } if create_with_tree: try: pipeline_tree = params["pipeline_tree"] for key, value in params["constants"].items(): if key in pipeline_tree["constants"]: if pipeline_tree["constants"][key].get("is_meta", False): meta = copy.deepcopy(pipeline_tree["constants"][key]) pipeline_tree["constants"][key]["meta"] = meta pipeline_tree["constants"][key]["value"] = value standardize_pipeline_node_name(pipeline_tree) validate_web_pipeline_tree(pipeline_tree) except Exception as e: message = "[API] create_task get invalid pipeline_tree: %s" % str( e) logger.exception(message) return { "result": False, "message": message, "code": err_code.UNKNOWN_ERROR.code } pipeline_instance_kwargs["pipeline_tree"] = pipeline_tree try: data = TaskFlowInstance.objects.create_pipeline_instance( template=tmpl, **pipeline_instance_kwargs) except PipelineException as e: message = "[API] create_task create pipeline error: %s" % str(e) logger.exception(message) return { "result": False, "message": message, "code": err_code.UNKNOWN_ERROR.code } else: # 如果请求参数中含有非空的execute_task_nodes_id(要执行的节点),就将其转换为exclude_task_nodes_id(要排除的节点) if not params["execute_task_nodes_id"]: exclude_task_nodes_id = params["exclude_task_nodes_id"] else: exclude_task_nodes_id = get_exclude_nodes_by_execute_nodes( params["execute_task_nodes_id"], tmpl) try: data = TaskFlowInstance.objects.create_pipeline_instance_exclude_task_nodes( tmpl, pipeline_instance_kwargs, params["constants"], exclude_task_nodes_id, params["simplify_vars"], ) except Exception as e: message = f"[API] create_task create pipeline without tree error: {e}" logger.exception(message) return { "result": False, "message": message, "code": err_code.UNKNOWN_ERROR.code } task = TaskFlowInstance.objects.create( project=project, pipeline_instance=data, category=tmpl.category, template_id=template_id, template_source=template_source, create_method="api", create_info=app_code, flow_type=params.get("flow_type", "common"), current_flow="execute_task" if params.get("flow_type", "common") == "common" else "func_claim", engine_ver=EngineConfig.objects.get_engine_ver( project_id=project.id, template_id=template_id, template_source=template_source), ) # crete auto retry strategy arn_creator = AutoRetryNodeStrategyCreator( taskflow_id=task.id, root_pipeline_id=task.pipeline_instance.instance_id) arn_creator.batch_create_strategy(task.pipeline_instance.execution_data) # create timeout config TimeoutNodeConfig.objects.batch_create_node_timeout_config( taskflow_id=task.id, root_pipeline_id=task.pipeline_instance.instance_id, pipeline_tree=task.pipeline_instance.execution_data, ) return { "result": True, "data": { "task_id": task.id, "task_url": task.url, "pipeline_tree": task.pipeline_tree }, "code": err_code.SUCCESS.code, }
def create_periodic_task(request, template_id, project_id): project = request.project # check if the periodic task of the project reach the limit periodic_task_limit = env.PERIODIC_TASK_PROJECT_MAX_NUMBER project_config = ProjectConfig.objects.filter( project_id=project.id).only("max_periodic_task_num").first() if project_config and project_config.max_periodic_task_num > 0: periodic_task_limit = project_config.max_periodic_task_num if PeriodicTask.objects.filter( project__id=project.id).count() >= periodic_task_limit: message = "Periodic task number reaches limit: {}".format( periodic_task_limit) return { "result": False, "message": message, "code": err_code.INVALID_OPERATION.code } params = json.loads(request.body) template_source = params.get("template_source", PROJECT) logger.info( "[API] apigw create_periodic_task info, " "template_id: {template_id}, project_id: {project_id}, params: {params}" .format(template_id=template_id, project_id=project.id, params=params)) if template_source in NON_COMMON_TEMPLATE_TYPES: template_source = PROJECT try: template = TaskTemplate.objects.get(pk=template_id, project_id=project.id, is_deleted=False) except TaskTemplate.DoesNotExist: result = { "result": False, "message": "template[id={template_id}] of project[project_id={project_id} , biz_id{biz_id}] " "does not exist".format( template_id=template_id, project_id=project.id, biz_id=project.bk_biz_id, ), "code": err_code.CONTENT_NOT_EXIST.code, } return result else: try: template = CommonTemplate.objects.get(id=template_id, is_deleted=False) except CommonTemplate.DoesNotExist: result = { "result": False, "message": "common template[id={template_id}] does not exist".format( template_id=template_id), "code": err_code.CONTENT_NOT_EXIST.code, } return result params.setdefault("constants", {}) params.setdefault("exclude_task_nodes_id", []) try: jsonschema.validate(params, APIGW_CREATE_PERIODIC_TASK_PARAMS) except jsonschema.ValidationError as e: logger.warning("[API] create_periodic_task raise prams error: %s" % e) message = "task params is invalid: %s" % e return { "result": False, "message": message, "code": err_code.REQUEST_PARAM_INVALID.code } exclude_task_nodes_id = params["exclude_task_nodes_id"] pipeline_tree = template.pipeline_tree try: PipelineTemplateWebPreviewer.preview_pipeline_tree_exclude_task_nodes( pipeline_tree, exclude_task_nodes_id) except Exception as e: logger.exception( "[API] create_periodic_task preview tree error: {}".format(e)) return { "result": False, "message": str(e), "code": err_code.UNKNOWN_ERROR.code } for key, val in list(params["constants"].items()): if key in pipeline_tree["constants"]: pipeline_tree["constants"][key]["value"] = val name = params["name"] cron = params["cron"] try: replace_template_id(TaskTemplate, pipeline_tree) except Exception as e: logger.exception( "[API] create_periodic_task replace id error: {}".format(e)) return { "result": False, "message": str(e), "code": err_code.UNKNOWN_ERROR.code } try: task = PeriodicTask.objects.create( project=project, template=template, template_source=template_source, name=name, cron=cron, pipeline_tree=pipeline_tree, creator=request.user.username, ) except Exception as e: logger.exception( "[API] create_periodic_task create error: {}".format(e)) return { "result": False, "message": str(e), "code": err_code.UNKNOWN_ERROR.code } data = info_data_from_period_task(task) return {"result": True, "data": data, "code": err_code.SUCCESS.code}
def dispatch_plugin_query(request): """ 转发插件表单渲染资源请求,暂时仅考虑GET/POST请求 body = { "url": 被转发资源请求url, 比如:/pipeline/job_get_script_list/4/?type=public "method": 'GET|POST', "data": data, POST请求的数据 } """ try: params = json.loads(request.body) except Exception: return { "result": False, "message": "invalid json format", "code": err_code.REQUEST_PARAM_INVALID.code, } # proxy: url/method/data url = params.get("url") method = params.get("method", "GET") data = params.get("data", {}) try: parsed = urlsplit(url) if method.lower() == "get": fake_request = RequestFactory().get( url, content_type="application/json") elif method.lower() == "post": fake_request = RequestFactory().post( url, data=data, content_type="application/json") else: return { "result": False, "code": err_code.INVALID_OPERATION.code, "message": "dispatch_plugin_query: only support get and post method.", } # transfer request.user setattr(fake_request, "user", request.user) # resolve view_func match = resolve(parsed.path, urlconf=None) view_func, kwargs = match.func, match.kwargs # call view_func return view_func(fake_request, **kwargs) except Resolver404: logger.warning( "dispatch_plugin_query: resolve view func 404 for: {}".format(url)) return { "result": False, "code": err_code.REQUEST_PARAM_INVALID.code, "message": "dispatch_plugin_query: resolve view func 404 for: {}".format(url), } except Exception as e: logger.exception("dispatch_plugin_query: exception for {}".format(e)) return { "result": False, "message": "dispatch_plugin_query: exception for {}".format(e), "code": err_code.UNKNOWN_ERROR.code, }