Example #1
0
    def bcs_single_app_perm_handler(self,
                                    request,
                                    project_id,
                                    muster_id,
                                    ns_id,
                                    source_type="模板集"):
        """针对具体资源的权限处理"""
        # 继承命名空间的权限
        resp = paas_cc.get_namespace(request.user.token.access_token,
                                     project_id, ns_id)
        data = resp.get('data')
        perm_ctx = NamespaceScopedPermCtx(
            username=request.user.username,
            project_id=project_id,
            cluster_id=data.get('cluster_id'),
            name=data.get('name'),
        )
        NamespaceScopedPermission().can_use(perm_ctx)

        if source_type == "模板集":
            muster_info = Template.objects.filter(id=muster_id,
                                                  is_deleted=False).first()
            if not muster_info:
                raise error_codes.CheckFailed(_("没有查询到模板集信息"))
            # 继承模板集的权限
            perm_ctx = TemplatesetPermCtx(username=request.user.username,
                                          project_id=project_id,
                                          template_id=muster_id)
            TemplatesetPermission().can_instantiate(perm_ctx)
Example #2
0
    def can_use_instance(cls,
                         request,
                         project_id,
                         ns_id,
                         tmpl_set_id=None,
                         source_type=SourceType.TEMPLATE):
        # 继承命名空间的权限
        resp = paas_cc.get_namespace(request.user.token.access_token,
                                     project_id, ns_id)
        data = resp.get('data')
        perm_ctx = NamespaceScopedPermCtx(
            username=request.user.username,
            project_id=project_id,
            cluster_id=data.get('cluster_id'),
            name=data.get('name'),
        )
        NamespaceScopedPermission().can_use(perm_ctx)

        if source_type == SourceType.TEMPLATE:
            tmpl_set_info = Template.objects.filter(id=tmpl_set_id).first()
            if not tmpl_set_info:
                raise error_codes.CheckFailed(
                    f"template:{tmpl_set_id} not found")
            # 继承模板集的权限
            perm_ctx = TemplatesetPermCtx(username=request.user.username,
                                          project_id=project_id,
                                          template_id=tmpl_set_id)
            TemplatesetPermission().can_instantiate(perm_ctx)
Example #3
0
    def post(self, request, project_id, pk):
        self.request = request
        self.project_id = project_id
        self.pk = pk
        template = validate_template_id(project_id,
                                        pk,
                                        is_return_tempalte=True)

        # 验证用户是否有编辑权限
        perm_ctx = TemplatesetPermCtx(username=request.user.username,
                                      project_id=project_id,
                                      template_id=pk)
        self.iam_perm.can_update(perm_ctx)

        # 检查模板集是否可操作(即未被加锁)
        check_template_available(template, request.user.username)

        # 验证模板名是否已经存在
        new_template_name = request.data.get("name")
        is_exist = (Template.default_objects.exclude(id=pk).filter(
            name=new_template_name, project_id=project_id).exists())
        if is_exist:
            detail = {"field": [_("模板集名称[{}]已经存在").format(new_template_name)]}
            raise ValidationError(detail=detail)

        self.slz = serializers_new.UpdateTemplateSLZ(data=request.data)
        self.slz.is_valid(raise_exception=True)

        return super(SingleTemplateView, self).update(self.slz)
Example #4
0
 def test_can_instantiate(self, templateset_permission_obj, project_id,
                          template_id):
     """测试场景:有模板集实例化权限"""
     perm_ctx = TemplatesetPermCtx(username=roles.ADMIN_USER,
                                   project_id=project_id,
                                   template_id=template_id)
     instantiate_templateset(perm_ctx)
Example #5
0
 def test_can_not_instantiate(self, templateset_permission_obj, project_id,
                              template_id):
     """测试场景:无模板集实例化权限(同时无项目查看权限)"""
     username = roles.ANONYMOUS_USER
     perm_ctx = TemplatesetPermCtx(username=username,
                                   project_id=project_id,
                                   template_id=template_id)
     with pytest.raises(PermissionDeniedError) as exec:
         templateset_permission_obj.can_instantiate(perm_ctx)
     assert exec.value.data['perms']['apply_url'] == generate_apply_url(
         username,
         [
             ActionResourcesRequest(
                 TemplatesetAction.INSTANTIATE,
                 resource_type=ResourceType.Templateset,
                 resources=[template_id],
                 parent_chain=[
                     IAMResource(ResourceType.Project, project_id)
                 ],
             ),
             ActionResourcesRequest(
                 TemplatesetAction.VIEW,
                 resource_type=ResourceType.Templateset,
                 resources=[template_id],
                 parent_chain=[
                     IAMResource(ResourceType.Project, project_id)
                 ],
             ),
             ActionResourcesRequest(ProjectAction.VIEW,
                                    resource_type=ResourceType.Project,
                                    resources=[project_id]),
         ],
     )
Example #6
0
    def validate_view_perms(self,
                            request,
                            project_id,
                            muster_id,
                            ns_id,
                            source_type="模板集"):
        """查询资源时, 校验用户的查询权限"""
        resp = paas_cc.get_namespace(request.user.token.access_token,
                                     project_id, ns_id)
        data = resp.get('data')
        perm_ctx = NamespaceScopedPermCtx(
            username=request.user.username,
            project_id=project_id,
            cluster_id=data.get('cluster_id'),
            name=data.get('name'),
        )
        NamespaceScopedPermission().can_view(perm_ctx)

        if source_type == "模板集":
            muster_info = Template.objects.filter(id=muster_id,
                                                  is_deleted=False).first()
            if not muster_info:
                raise error_codes.CheckFailed(_("没有查询到模板集信息"))
            perm_ctx = TemplatesetPermCtx(username=request.user.username,
                                          project_id=project_id,
                                          template_id=muster_id)
            TemplatesetPermission().can_view(perm_ctx)
Example #7
0
    def can_edit_template(self, request, template):
        # 验证模板是否被其他用户加锁
        validate_template_locked(template, request.user.username)

        perm_ctx = TemplatesetPermCtx(
            username=request.user.username, project_id=template.project_id, template_id=template.id
        )
        self.iam_perm.can_update(perm_ctx)
Example #8
0
    def put(self, request, project_id, pk):
        """复制模板"""
        self.request = request

        validate_template_id(project_id, pk, is_return_tempalte=True)

        perm_ctx = TemplatesetPermCtx(username=request.user.username,
                                      project_id=project_id,
                                      template_id=pk)
        self.iam_perm.can_copy(perm_ctx)

        self.project_id = project_id
        self.pk = pk
        data = request.data
        data["project_id"] = project_id
        self.slz = TemplateCreateSLZ(data=data)
        self.slz.is_valid(raise_exception=True)
        new_template_name = self.slz.data["name"]
        # 验证模板名是否已经存在
        is_exist = Template.default_objects.filter(
            name=new_template_name, project_id=project_id).exists()
        if is_exist:
            detail = {"field": [_("模板集名称[{}]已经存在").format(new_template_name)]}
            raise ValidationError(detail=detail)
        # 验证 old模板集id 是否正确
        old_tems = self.get_queryset()
        if not old_tems.exists():
            detail = {"field": [_("要复制的模板集不存在")]}
            raise ValidationError(detail=detail)
        old_tem = old_tems.first()

        username = request.user.username
        template_id, version_id, show_version_id = old_tem.copy_tempalte(
            project_id, new_template_name, username)

        self.iam_perm.grant_resource_creator_actions(
            TemplatesetCreatorAction(template_id=template_id,
                                     name=new_template_name,
                                     project_id=project_id,
                                     creator=username), )

        # 记录操作日志
        request.audit_ctx.update_fields(resource=new_template_name,
                                        resource_id=template_id,
                                        description=_("复制模板集"))
        return Response({
            "code": 0,
            "message": "OK",
            "data": {
                "template_id": template_id,
                "version_id": version_id,
                "show_version_id": show_version_id
            },
        })
Example #9
0
def update_template_with_perm_check(request, template, tmpl_args):
    validate_template_locked(template, request.user.username)

    # 验证用户是否有编辑权限
    perm_ctx = TemplatesetPermCtx(username=request.user.username,
                                  project_id=template.project_id,
                                  template_id=template.id)
    TemplatesetPermission().can_update(perm_ctx)

    audit_ctx = AuditContext(user=request.user.username,
                             project_id=template.project_id)
    template = update_template(audit_ctx, request.user.username, template,
                               tmpl_args)
    return template
Example #10
0
def create_template_with_perm_check(request, project_id, tmpl_args):
    permission = TemplatesetPermission()
    perm_ctx = TemplatesetPermCtx(username=request.user.username,
                                  project_id=project_id)
    permission.can_create(perm_ctx)

    audit_ctx = AuditContext(user=request.user.username, project_id=project_id)
    template = create_template(audit_ctx, request.user.username, project_id,
                               tmpl_args)

    permission.grant_resource_creator_actions(
        TemplatesetCreatorAction(template_id=str(template.id),
                                 name=template.name,
                                 project_id=project_id,
                                 creator=request.user.username), )

    return template
Example #11
0
 def test_can_instantiate_but_no_project(self, templateset_permission_obj,
                                         project_id, template_id):
     """测试场景:有模板集实例化权限(同时无项目查看权限)"""
     username = roles.TEMPLATESET_NO_PROJECT_USER
     perm_ctx = TemplatesetPermCtx(username=username,
                                   project_id=project_id,
                                   template_id=template_id)
     with pytest.raises(PermissionDeniedError) as exec:
         templateset_permission_obj.can_instantiate(perm_ctx)
     assert exec.value.data['perms']['apply_url'] == generate_apply_url(
         username,
         [
             ActionResourcesRequest(ProjectAction.VIEW,
                                    resource_type=ResourceType.Project,
                                    resources=[project_id])
         ],
     )
Example #12
0
def _delete_old_init_templates(template_qsets, project_id, project_code,
                               access_token, username):
    for template in template_qsets:
        template_id = template.id

        perm_ctx = TemplatesetPermCtx(username=username,
                                      project_id=project_id,
                                      template_id=template_id)
        TemplatesetPermission().can_delete(perm_ctx)

        VersionedEntity.objects.filter(template_id=template_id).delete()
        ShowVersion.objects.filter(template_id=template_id,
                                   name='init_version').delete()

        template.name = f'[deleted_{int(time.time())}]{template.name}'
        template.is_deleted = True
        template.deleted_time = timezone.now()
        template.save(update_fields=['name', 'is_deleted', 'deleted_time'])
Example #13
0
    def delete(self, request, project_id, pk):
        self.request = request
        self.project_id = project_id
        self.pk = pk
        # 验证用户是否删除权限
        template = validate_template_id(project_id,
                                        pk,
                                        is_return_tempalte=True)

        perm_ctx = TemplatesetPermCtx(username=request.user.username,
                                      project_id=project_id,
                                      template_id=pk)
        self.iam_perm.can_delete(perm_ctx)

        # 检查模板集是否可操作(即未被加锁)
        check_template_available(template, request.user.username)

        # 已经实例化过的版本,不能被删除
        exist_version = is_tempalte_instance(pk)
        if exist_version:
            return Response({
                "code": 400,
                "message": _("模板集已经被实例化过,不能被删除"),
                "data": {}
            })
        instance = self.get_queryset().first()

        request.audit_ctx.update_fields(resource=instance.name,
                                        resource_id=instance.id,
                                        description=_("删除模板集"))

        # 删除后名称添加 [deleted]前缀
        _del_prefix = f"[deleted_{int(time.time())}]"
        del_tem_name = f"{_del_prefix}{instance.name}"
        self.get_queryset().update(name=del_tem_name,
                                   is_deleted=True,
                                   deleted_time=timezone.now())

        return Response({"code": 0, "message": "OK", "data": {"id": pk}})
Example #14
0
    def get(self, request, project_id, pk):
        self.request = request
        self.project_id = project_id
        self.pk = pk

        validate_template_id(project_id, pk, is_return_tempalte=True)

        perm_ctx = TemplatesetPermCtx(username=request.user.username,
                                      project_id=project_id,
                                      template_id=pk)
        self.iam_perm.can_view(perm_ctx)

        # 获取项目类型
        kind = request.project.kind

        tems = self.get_queryset()
        if tems:
            tem = tems.first()
            data = get_template_info(tem, kind)
        else:
            data = {}

        return PermsResponse(data, TemplatesetRequest(project_id=project_id))
Example #15
0
 def can_view_template(self, request, template):
     # 验证用户是否有查看权限
     perm_ctx = TemplatesetPermCtx(
         username=request.user.username, project_id=template.project_id, template_id=template.id
     )
     self.iam_perm.can_view(perm_ctx)
Example #16
0
    def test_can_not_instantiate_in_ns(
        self,
        templateset_permission_obj,
        namespace_scoped_permission_obj,
        project_id,
        template_id,
        cluster_id,
        namespace,
    ):
        """测试场景:有模板集实例化权限(但是无实例化到命名空间的权限)"""
        username = roles.PROJECT_TEMPLATESET_USER
        perm_ctx = TemplatesetPermCtx(username=username,
                                      project_id=project_id,
                                      template_id=template_id)
        with pytest.raises(PermissionDeniedError) as exec:
            templateset_permission_obj.can_instantiate_in_ns(
                perm_ctx, cluster_id, namespace)

        iam_ns_id = calc_iam_ns_id(cluster_id, namespace)
        assert exec.value.data['perms']['apply_url'] == generate_apply_url(
            username,
            [
                ActionResourcesRequest(
                    NamespaceScopedAction.CREATE,
                    ResourceType.Namespace,
                    resources=[iam_ns_id],
                    parent_chain=[
                        IAMResource(ResourceType.Project, project_id),
                        IAMResource(ResourceType.Cluster, cluster_id),
                    ],
                ),
                ActionResourcesRequest(
                    NamespaceScopedAction.VIEW,
                    ResourceType.Namespace,
                    resources=[iam_ns_id],
                    parent_chain=[
                        IAMResource(ResourceType.Project, project_id),
                        IAMResource(ResourceType.Cluster, cluster_id),
                    ],
                ),
                ActionResourcesRequest(
                    NamespaceScopedAction.UPDATE,
                    ResourceType.Namespace,
                    resources=[iam_ns_id],
                    parent_chain=[
                        IAMResource(ResourceType.Project, project_id),
                        IAMResource(ResourceType.Cluster, cluster_id),
                    ],
                ),
                ActionResourcesRequest(
                    NamespaceScopedAction.DELETE,
                    ResourceType.Namespace,
                    resources=[iam_ns_id],
                    parent_chain=[
                        IAMResource(ResourceType.Project, project_id),
                        IAMResource(ResourceType.Cluster, cluster_id),
                    ],
                ),
                ActionResourcesRequest(
                    NamespaceAction.VIEW,
                    ResourceType.Namespace,
                    resources=[iam_ns_id],
                    parent_chain=[
                        IAMResource(ResourceType.Project, project_id),
                        IAMResource(ResourceType.Cluster, cluster_id),
                    ],
                ),
                ActionResourcesRequest(
                    ClusterAction.VIEW,
                    ResourceType.Cluster,
                    resources=[cluster_id],
                    parent_chain=[
                        IAMResource(ResourceType.Project, project_id)
                    ],
                ),
                ActionResourcesRequest(ProjectAction.VIEW,
                                       ResourceType.Project,
                                       resources=[project_id]),
            ],
        )
Example #17
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_ctx = TemplatesetPermCtx(username=request.user.username,
                                      project_id=project_id,
                                      template_id=template.id)
        TemplatesetPermission().can_instantiate(perm_ctx)

        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

        # 判断 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{}").format("\n".join(ns_name_list)),
                "data":
                ns_name_list,
            })

        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,
                                   project_kind=request.project.kind)
        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']:
            TemplatesetAuditor(audit_ctx=AuditContext(
                project_id=project_id,
                user=username,
                resource=temp_name,
                resource_id=self.template_id,
                extra=self.instance_entity,
                description=_("实例化模板集[{}]命名空间[{}]").format(
                    temp_name, i['ns_name']),
                activity_type=ActivityType.Add,
                activity_status=ActivityStatus.Succeed,
            )).log_raw()

        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 = _("实例化模板集[{}]命名空间[{}],在实例化{}时失败,错误消息:{}").format(
                    temp_name, i['ns_name'], i['res_type'], i['err_msg'])
                failed_ns_name_list.append(
                    _("{}(实例化{}时)").format(i['ns_name'], i['res_type']))
            else:
                description = _("实例化模板集[{}]命名空间[{}]失败,错误消息:{}").format(
                    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

            TemplatesetAuditor(audit_ctx=AuditContext(
                project_id=project_id,
                user=username,
                resource=temp_name,
                resource_id=self.template_id,
                extra=self.instance_entity,
                description=description,
                activity_type=ActivityType.Add,
                activity_status=ActivityStatus.Failed,
            )).log_raw()

            if is_show_failed_msg:
                msg = '\n'.join(failed_msg)
            else:
                msg = _("以下命名空间实例化失败,\n{},请联系集群管理员解决").format(
                    "\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 #18
0
 def can_use_template(self, request, template):
     # 验证用户是否有使用权限
     perm_ctx = TemplatesetPermCtx(
         username=request.user.username, project_id=template.project_id, template_id=template.id
     )
     self.iam_perm.can_instantiate(perm_ctx)
Example #19
0
    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_ctx = TemplatesetPermCtx(username=request.user.username,
                                      project_id=project_id,
                                      template_id=template.id)
        TemplatesetPermission().can_instantiate(perm_ctx)

        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_id = slz_data['namespace']
        lb_info = slz_data.get('lb_info', {})

        resp = paas_cc.get_namespace(access_token, project_id, namespace_id)
        if resp.get('code') != 0:
            return Response({
                'code':
                400,
                'message':
                f"查询命名空间(namespace_id:{project_id}-{namespace_id})出错:{resp.get('message')}",
            })

        namespace_info = resp['data']
        perm_ctx = NamespaceScopedPermCtx(
            username=username,
            project_id=project_id,
            cluster_id=namespace_info['cluster_id'],
            name=namespace_info['name'],
        )
        NamespaceScopedPermission().can_use(perm_ctx)

        # 查询当前命名空间的变量信息
        variable_dict = slz_data.get('variable_info',
                                     {}).get(namespace_id) 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_id, instance_entity, **params)
        return Response({"code": 0, "message": "OK", "data": data})