Example #1
0
    def post(self, request, project_id):
        """实例化模板
        """
        # 参数验证
        self.project_id = project_id
        version_id = request.data.get('version_id')
        show_version_id = request.data.get('show_version_id')

        template, version_entity = validate_version_id(
            project_id,
            version_id,
            is_return_all=True,
            show_version_id=show_version_id)
        # 验证用户是否有使用权限
        perm = bcs_perm.Templates(request, project_id, template.id,
                                  template.name)
        perm.can_use(raise_exception=True)

        self.template_id = version_entity.template_id
        tem_instance_entity = version_entity.get_version_instance_resource_ids

        project_kind = request.project.kind
        self.slz = VersionInstanceCreateOrUpdateSLZ(
            data=request.data, context={'project_kind': project_kind})
        self.slz.is_valid(raise_exception=True)
        slz_data = self.slz.data

        # 验证前端传过了的预览资源是否在该版本的资源
        req_instance_entity = slz_data.get('instance_entity') or {}
        self.instance_entity = validate_instance_entity(
            req_instance_entity, tem_instance_entity)

        namespaces = slz_data['namespaces']
        ns_list = namespaces.split(',') if namespaces else []

        access_token = self.request.user.token.access_token
        username = self.request.user.username

        # 验证关联lb情况下,lb 是否都已经选中
        service_id_list = self.instance_entity.get('service') or []
        v_res, err_list, err_msg = validate_lb_info_by_version_id(
            access_token, project_id, version_entity, ns_list,
            slz_data.get('lb_info', {}), service_id_list)
        if not v_res:
            return Response({
                "code": 400,
                "message": err_msg,
                "data": err_list
            })

        # 判断 template 下 前台传过来的 namespace 是否已经实例化过
        res, ns_name_list, namespace_dict = validate_ns_by_tempalte_id(
            self.template_id, ns_list, access_token, project_id,
            req_instance_entity)
        if not res:
            return Response({
                "code":
                400,
                "message":
                "以下命名空间已经实例化过,不能再实例化\n%s" % "\n".join(ns_name_list),
                "data":
                ns_name_list
            })

        # 在数据平台创建项目信息
        cc_app_id = request.project.cc_app_id
        english_name = request.project.english_name
        create_data_project(request.user.username, project_id, cc_app_id,
                            english_name)
        # 创建/启动标准日志采集任务
        create_and_start_standard_data_flow(username, project_id, cc_app_id)

        slz_data['ns_list'] = ns_list
        slz_data['instance_entity'] = self.instance_entity
        slz_data['template_id'] = self.template_id
        slz_data['project_id'] = project_id
        slz_data['version_id'] = version_id
        slz_data['show_version_id'] = show_version_id

        result = handle_all_config(slz_data, access_token, username)
        instance_entity = slz_data.get("instance_entity")
        all_tmpl_name_dict = self.get_tmpl_name(instance_entity)

        # 添加操作记录
        temp_name = version_entity.get_template_name()
        for i in result['success']:
            client.ContextActivityLogClient(
                project_id=project_id,
                user=username,
                resource_type="template",
                resource=temp_name,
                resource_id=self.template_id,
                extra=json.dumps(self.instance_entity),
                description=u"实例化模板集[%s]命名空间[%s]" %
                (temp_name, i['ns_name'])).log_add(activity_status="succeed")

        failed_ns_name_list = []
        failed_msg = []
        is_show_failed_msg = False
        # 针对createError的触发后台任务轮训
        if result.get('failed'):
            check_instance_status.delay(request.user.token.access_token,
                                        project_id,
                                        request.project.get("kind"),
                                        all_tmpl_name_dict, result['failed'])
        for i in result['failed']:
            if i['res_type']:
                description = "实例化模板集[%s]命名空间[%s],在实例化%s时失败,错误消息:%s" % (
                    temp_name, i['ns_name'], i['res_type'], i['err_msg'])
                failed_ns_name_list.append("%s(实例化%s时)" %
                                           (i['ns_name'], i['res_type']))
            else:
                description = "实例化模板集[%s]命名空间[%s]失败,错误消息:%s" % (
                    temp_name, i['ns_name'], i['err_msg'])
                failed_ns_name_list.append(i['ns_name'])
                if i.get('show_err_msg'):
                    failed_msg.append(i['err_msg'])
                    is_show_failed_msg = True

            client.ContextActivityLogClient(
                project_id=project_id,
                user=username,
                resource_type="template",
                resource=temp_name,
                resource_id=self.template_id,
                extra=json.dumps(self.instance_entity),
                description=description).log_add(activity_status="failed")

            if is_show_failed_msg:
                msg = '\n'.join(failed_msg)
            else:
                msg = "以下命名空间实例化失败,\n%s,请联系集群管理员解决" % "\n".join(
                    failed_ns_name_list)
            if failed_ns_name_list:
                return Response({
                    "code": 400,
                    "message": msg,
                    "data": failed_ns_name_list
                })

        return Response({
            "code": 0,
            "message": "OK",
            "data": {
                "version_id": version_id,
                "template_id": self.template_id,
            }
        })
Example #2
0
class VersionInstanceView(viewsets.ViewSet):
    renderer_classes = (BKAPIRenderer, BrowsableAPIRenderer)

    def preview_config(self, request, project_id):
        project_kind = request.project.kind
        serializer = PreviewInstanceSLZ(data=request.data,
                                        context={'project_kind': project_kind})
        serializer.is_valid(raise_exception=True)
        slz_data = serializer.data

        # 验证 version_id 是否属于该项目
        version_id = slz_data['version_id']
        show_version_id = slz_data['show_version_id']

        template, version_entity = validate_version_id(
            project_id,
            version_id,
            is_return_all=True,
            show_version_id=show_version_id)
        # 验证用户是否有使用权限
        perm = bcs_perm.Templates(request, project_id, template.id,
                                  template.name)
        perm.can_use(raise_exception=True)

        template_id = version_entity.template_id
        version = version_entity.version
        tem_instance_entity = version_entity.get_version_instance_resource_ids

        # 验证前端传过了的预览资源是否在该版本的资源
        req_instance_entity = slz_data.get('instance_entity') or {}
        instance_entity = validate_instance_entity(req_instance_entity,
                                                   tem_instance_entity)

        access_token = self.request.user.token.access_token
        username = self.request.user.username

        namespace = slz_data['namespace']
        lb_info = slz_data.get('lb_info', {})
        # 验证关联lb情况下,lb 是否都已经选中
        service_id_list = instance_entity.get('service') or []
        v_res, err_list, err_msg = validate_lb_info_by_version_id(
            access_token, project_id, version_entity, [namespace], lb_info,
            service_id_list)
        if not v_res:
            return Response({
                "code": 400,
                "message": err_msg,
                "data": err_list
            })
        # 在数据平台创建项目信息
        cc_app_id = request.project.cc_app_id
        english_name = request.project.english_name
        create_data_project(request.user.username, project_id, cc_app_id,
                            english_name)

        # 查询当前命名空间的变量信息
        variable_dict = slz_data.get('variable_info', {}).get(namespace) or {}
        params = {
            "instance_id": "instanceID",
            "version_id": version_id,
            "show_version_id": show_version_id,
            "template_id": template_id,
            "version": version,
            "project_id": project_id,
            "access_token": access_token,
            "username": username,
            "lb_info": lb_info,
            "variable_dict": variable_dict,
            "is_preview": True
        }
        data = preview_config_json(namespace, instance_entity, **params)
        return Response({"code": 0, "message": "OK", "data": data})

    def get_tmpl_name(self, instance_entity):
        all_tmpl_name_dict = {}
        for category, tmpl_id_list in instance_entity.items():
            # 需要单独处理 Metric, 不需要轮询Metric 的状态
            # 非标准日志采集相关的 configmap\K8sConfigMap 不需要轮询状态
            # secret 相关的也不需要轮询状态
            if category in [
                    'metric', 'configmap', 'K8sConfigMap', 'secret',
                    'K8sSecret'
            ]:
                continue

            if category not in MODULE_DICT:
                raise error_codes.CheckFailed.f("类型只能为%s" %
                                                ";".join(MODULE_DICT.keys()))
            tmpl_name = MODULE_DICT[category].objects.filter(
                id__in=tmpl_id_list).values_list("name", flat=True)
            if category in all_tmpl_name_dict:
                all_tmpl_name_dict[category].extend(list(tmpl_name))
            else:
                all_tmpl_name_dict = {category: list(tmpl_name)}
        return all_tmpl_name_dict

    def post(self, request, project_id):
        """实例化模板
        """
        # 参数验证
        self.project_id = project_id
        version_id = request.data.get('version_id')
        show_version_id = request.data.get('show_version_id')

        template, version_entity = validate_version_id(
            project_id,
            version_id,
            is_return_all=True,
            show_version_id=show_version_id)
        # 验证用户是否有使用权限
        perm = bcs_perm.Templates(request, project_id, template.id,
                                  template.name)
        perm.can_use(raise_exception=True)

        self.template_id = version_entity.template_id
        tem_instance_entity = version_entity.get_version_instance_resource_ids

        project_kind = request.project.kind
        self.slz = VersionInstanceCreateOrUpdateSLZ(
            data=request.data, context={'project_kind': project_kind})
        self.slz.is_valid(raise_exception=True)
        slz_data = self.slz.data

        # 验证前端传过了的预览资源是否在该版本的资源
        req_instance_entity = slz_data.get('instance_entity') or {}
        self.instance_entity = validate_instance_entity(
            req_instance_entity, tem_instance_entity)

        namespaces = slz_data['namespaces']
        ns_list = namespaces.split(',') if namespaces else []

        access_token = self.request.user.token.access_token
        username = self.request.user.username

        # 验证关联lb情况下,lb 是否都已经选中
        service_id_list = self.instance_entity.get('service') or []
        v_res, err_list, err_msg = validate_lb_info_by_version_id(
            access_token, project_id, version_entity, ns_list,
            slz_data.get('lb_info', {}), service_id_list)
        if not v_res:
            return Response({
                "code": 400,
                "message": err_msg,
                "data": err_list
            })

        # 判断 template 下 前台传过来的 namespace 是否已经实例化过
        res, ns_name_list, namespace_dict = validate_ns_by_tempalte_id(
            self.template_id, ns_list, access_token, project_id,
            req_instance_entity)
        if not res:
            return Response({
                "code":
                400,
                "message":
                "以下命名空间已经实例化过,不能再实例化\n%s" % "\n".join(ns_name_list),
                "data":
                ns_name_list
            })

        # 在数据平台创建项目信息
        cc_app_id = request.project.cc_app_id
        english_name = request.project.english_name
        create_data_project(request.user.username, project_id, cc_app_id,
                            english_name)
        # 创建/启动标准日志采集任务
        create_and_start_standard_data_flow(username, project_id, cc_app_id)

        slz_data['ns_list'] = ns_list
        slz_data['instance_entity'] = self.instance_entity
        slz_data['template_id'] = self.template_id
        slz_data['project_id'] = project_id
        slz_data['version_id'] = version_id
        slz_data['show_version_id'] = show_version_id

        result = handle_all_config(slz_data, access_token, username)
        instance_entity = slz_data.get("instance_entity")
        all_tmpl_name_dict = self.get_tmpl_name(instance_entity)

        # 添加操作记录
        temp_name = version_entity.get_template_name()
        for i in result['success']:
            client.ContextActivityLogClient(
                project_id=project_id,
                user=username,
                resource_type="template",
                resource=temp_name,
                resource_id=self.template_id,
                extra=json.dumps(self.instance_entity),
                description=u"实例化模板集[%s]命名空间[%s]" %
                (temp_name, i['ns_name'])).log_add(activity_status="succeed")

        failed_ns_name_list = []
        failed_msg = []
        is_show_failed_msg = False
        # 针对createError的触发后台任务轮训
        if result.get('failed'):
            check_instance_status.delay(request.user.token.access_token,
                                        project_id,
                                        request.project.get("kind"),
                                        all_tmpl_name_dict, result['failed'])
        for i in result['failed']:
            if i['res_type']:
                description = "实例化模板集[%s]命名空间[%s],在实例化%s时失败,错误消息:%s" % (
                    temp_name, i['ns_name'], i['res_type'], i['err_msg'])
                failed_ns_name_list.append("%s(实例化%s时)" %
                                           (i['ns_name'], i['res_type']))
            else:
                description = "实例化模板集[%s]命名空间[%s]失败,错误消息:%s" % (
                    temp_name, i['ns_name'], i['err_msg'])
                failed_ns_name_list.append(i['ns_name'])
                if i.get('show_err_msg'):
                    failed_msg.append(i['err_msg'])
                    is_show_failed_msg = True

            client.ContextActivityLogClient(
                project_id=project_id,
                user=username,
                resource_type="template",
                resource=temp_name,
                resource_id=self.template_id,
                extra=json.dumps(self.instance_entity),
                description=description).log_add(activity_status="failed")

            if is_show_failed_msg:
                msg = '\n'.join(failed_msg)
            else:
                msg = "以下命名空间实例化失败,\n%s,请联系集群管理员解决" % "\n".join(
                    failed_ns_name_list)
            if failed_ns_name_list:
                return Response({
                    "code": 400,
                    "message": msg,
                    "data": failed_ns_name_list
                })

        return Response({
            "code": 0,
            "message": "OK",
            "data": {
                "version_id": version_id,
                "template_id": self.template_id,
            }
        })