Ejemplo n.º 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)
Ejemplo n.º 2
0
    def check_namespace_use_perm(self, request, project_id, namespace_list):
        """检查是否有命名空间的使用权限"""
        access_token = request.user.token.access_token

        # 根据 namespace  查询 ns_id
        namespace_res = paas_cc.get_namespace_list(access_token,
                                                   project_id,
                                                   limit=LIMIT_FOR_ALL_DATA)
        namespace_data = namespace_res.get('data', {}).get('results') or []
        namespace_dict = {i['name']: i['id'] for i in namespace_data}
        namespace_cluster_dict = {
            i['name']: i['cluster_id']
            for i in namespace_data
        }

        for namespace in namespace_list:
            # 检查是否有命名空间的使用权限
            perm_ctx = NamespaceScopedPermCtx(
                username=request.user.username,
                project_id=project_id,
                cluster_id=namespace_cluster_dict.get(namespace),
                name=namespace,
            )
            self.iam_perm.can_use(perm_ctx)
        return namespace_dict
Ejemplo n.º 3
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)
Ejemplo n.º 4
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)
Ejemplo n.º 5
0
    def update(self, instance, validated_data):
        ns_info = self.get_ns_info_by_id(instance.namespace_id)

        perm_ctx = NamespaceScopedPermCtx(
            username=self.context["request"].user.username,
            project_id=instance.project_id,
            cluster_id=ns_info['cluster_id'],
            name=ns_info['name'],
        )
        NamespaceScopedPermission().can_update(perm_ctx)

        # update sys variable
        sys_variables = collect_system_variable(
            access_token=self.context["request"].user.token.access_token,
            project_id=instance.project_id,
            namespace_id=instance.namespace_id,
        )

        return instance.upgrade_app(
            access_token=self.access_token,
            chart_version_id=validated_data["upgrade_verion"],
            answers=validated_data["get_answers"],
            customs=validated_data["get_customs"],
            valuefile=validated_data.get("get_valuefile"),
            updator=self.request_username,
            sys_variables=sys_variables,
            valuefile_name=validated_data.get("get_valuefile_name"),
            cmd_flags=validated_data["cmd_flags"],
        )
Ejemplo n.º 6
0
    def preview_or_apply(self, request, project_id, template_id,
                         show_version_id):
        """
        request.data = {
            'is_preview': True,
            'namespace_id': 'test',
            'template_files': [{
                'resource_name': 'Deployment',
                'files': [{'name': 'nginx.yaml', 'id': 3}]
            }],
            'template_variables': {}
        }
        """
        data = self._request_data(request,
                                  project_id=project_id,
                                  template_id=template_id,
                                  show_version_id=show_version_id)
        serializer = serializers.TemplateReleaseSLZ(data=data)
        serializer.is_valid(raise_exception=True)
        validated_data = serializer.validated_data

        template = validated_data["show_version"]["template"]
        self.can_use_template(request, template)

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

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

        processor = ReleaseDataProcessor(
            user=self.request.user,
            raw_release_data=self._raw_release_data(project_id,
                                                    validated_data))
        release_data = processor.release_data()

        if validated_data["is_preview"]:
            return Response(release_data.template_files)

        controller = DeployController(user=self.request.user,
                                      release_data=release_data)
        controller.apply()

        return Response()
Ejemplo n.º 7
0
def can_use_namespaces(request, project_id, namespaces):
    """
    namespaces: [(cluster_id, ns_name)]
    """
    permission = NamespaceScopedPermission()
    for ns in namespaces:
        perm_ctx = NamespaceScopedPermCtx(
            username=request.user.username, project_id=project_id, cluster_id=ns[0], name=ns[1]
        )
        permission.can_use(perm_ctx)
Ejemplo n.º 8
0
 def _validate_namespace_info(self, data):
     request = self.context["request"]
     namespace_info = data["namespace_info"]
     namespace_info["id"] = get_namespace_id(
         request.user.token.access_token, data["project_id"],
         namespace_info["cluster_id"], namespace_info["name"])
     perm_ctx = NamespaceScopedPermCtx(
         username=request.user.username,
         project_id=data["project_id"],
         cluster_id=namespace_info["cluster_id"],
         name=namespace_info["name"],
     )
     NamespaceScopedPermission().can_use(perm_ctx)
Ejemplo n.º 9
0
    def _validate_namespace_use_perm(self, project_id: str, cluster_id: str,
                                     namespaces: List):
        """检查是否有命名空间的使用权限"""
        permission = NamespaceScopedPermission()
        for ns in namespaces:
            if ns in constants.SM_NO_PERM_NAMESPACE:
                raise error_codes.APIError(_('不允许操作命名空间 {}').format(ns))

            # 检查是否有命名空间的使用权限
            # TODO 针对多个,考虑批量去解
            perm_ctx = NamespaceScopedPermCtx(
                username=self.request.user.username,
                project_id=project_id,
                cluster_id=cluster_id,
                name=ns)
            permission.can_use(perm_ctx)
Ejemplo n.º 10
0
    def _can_use_namespaces(self, request, project_id, data, ns_name_id_map):
        permission = NamespaceScopedPermission()
        for info in data:
            # 通过集群id和namespace名称确认namespace id,判断是否有namespace权限
            ns_id = ns_name_id_map.get((info["cluster_id"], info["namespace"]))
            if not ns_id:
                raise ValidationError(
                    _("集群:{}下没有查询到namespace:{}").format(
                        info["cluster_id"], info["namespace"]))

            perm_ctx = NamespaceScopedPermCtx(
                username=request.user.username,
                project_id=project_id,
                cluster_id=info["cluster_id"],
                name=info["namespace"],
            )
            permission.can_use(perm_ctx)
Ejemplo n.º 11
0
    def update_resource(self, request, project_id, cluster_id, namespace,
                        name):
        """更新"""
        if get_cluster_type(cluster_id) == ClusterType.SHARED:
            return Response({"code": 400, "message": _("无法操作共享集群资源")})

        access_token = request.user.token.access_token

        if namespace in K8S_SYS_NAMESPACE:
            return Response({
                "code":
                400,
                "message":
                _("不允许操作系统命名空间[{}]").format(','.join(K8S_SYS_NAMESPACE)),
                "data": {}
            })

        request_data = request.data or {}
        request_data['project_id'] = project_id
        # 验证请求参数
        slz = self.slz(data=request.data)
        slz.is_valid(raise_exception=True)
        data = slz.data

        try:
            config = json.loads(data["config"])
        except Exception:
            config = data["config"]
        namespace_id = data['namespace_id']
        username = request.user.username

        # 检查是否有命名空间的使用权限
        perm_ctx = NamespaceScopedPermCtx(username=username,
                                          project_id=project_id,
                                          cluster_id=cluster_id,
                                          name=namespace)
        NamespaceScopedPermission().can_use(perm_ctx)

        # 对配置文件做处理
        gparams = {
            "access_token": access_token,
            "project_id": project_id,
            "username": username
        }
        generator = GENERATOR_DICT.get(self.cate)(0, namespace_id, **gparams)
        config = generator.handle_db_config(db_config=config)
        # 获取上下文信息
        context = generator.context
        now_time = context.get('SYS_UPDATE_TIME')
        instance_id = data.get('instance_id', 0)
        context.update({
            'SYS_CREATOR': data.get('creator', ''),
            'SYS_CREATE_TIME': data.get('create_time', ''),
            'SYS_INSTANCE_ID': instance_id,
        })

        # 生成配置文件
        sys_config = copy.deepcopy(self.sys_config)
        resource_config = update_nested_dict(config, sys_config)
        resource_config = json.dumps(resource_config)
        try:
            config_profile = render_mako_context(resource_config, context)
        except Exception:
            logger.exception(u"配置文件变量替换出错\nconfig:%s\ncontext:%s" %
                             (resource_config, context))
            raise ValidationError(_("配置文件中有未替换的变量"))

        config_profile = generator.format_config_profile(config_profile)

        service_name = config.get('metadata', {}).get('name')
        _config_content = {
            'name': service_name,
            'config': json.loads(config_profile),
            'context': context
        }

        # 更新db中的数据
        config_objs = InstanceConfig.objects.filter(
            namespace=namespace_id,
            category=self.cate,
            name=service_name,
        )
        if config_objs.exists():
            config_objs.update(
                creator=username,
                updator=username,
                oper_type='update',
                updated=now_time,
                is_deleted=False,
            )
            _instance_config = config_objs.first()
        else:
            _instance_config = InstanceConfig.objects.create(
                namespace=namespace_id,
                category=self.cate,
                name=service_name,
                config=config_profile,
                instance_id=instance_id,
                creator=username,
                updator=username,
                oper_type='update',
                updated=now_time,
                is_deleted=False,
            )
        _config_content['instance_config_id'] = _instance_config.id
        configuration = {namespace_id: {self.cate: [_config_content]}}

        driver = get_scheduler_driver(access_token, project_id, configuration,
                                      request.project.kind)
        result = driver.instantiation(is_update=True)

        failed = []
        if isinstance(result, dict):
            failed = result.get('failed') or []
        # 添加操作审计
        activity_client.ContextActivityLogClient(
            project_id=project_id,
            user=username,
            resource_type="instance",
            resource=service_name,
            resource_id=_instance_config.id,
            extra=json.dumps(configuration),
            description=_("更新{}[{}]命名空间[{}]").format(self.category,
                                                     service_name, namespace),
        ).log_modify(activity_status="failed" if failed else "succeed")

        if failed:
            return Response({
                "code":
                400,
                "message":
                _("{}[{}]在命名空间[{}]更新失败,请联系集群管理员解决").format(
                    self.category, service_name, namespace),
                "data": {},
            })
        return Response({"code": 0, "message": "OK", "data": {}})
Ejemplo n.º 12
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})
Ejemplo n.º 13
0
    def update_services(self, request, project_id, cluster_id, namespace,
                        name):
        """更新 service"""
        if get_cluster_type(cluster_id) == ClusterType.SHARED:
            return Response({"code": 400, "message": _("无法操作共享集群资源")})

        access_token = request.user.token.access_token
        flag, project_kind = self.get_project_kind(request, project_id)
        if not flag:
            return project_kind

        if namespace in K8S_SYS_NAMESPACE:
            return Response({
                "code":
                400,
                "message":
                _("不允许操作系统命名空间[{}]").format(','.join(K8S_SYS_NAMESPACE)),
                "data": {}
            })
        # k8s 相关数据
        slz_class = K8sServiceCreateOrUpdateSLZ
        s_sys_con = K8S_SEVICE_SYS_CONFIG
        s_cate = 'K8sService'

        request_data = request.data or {}
        request_data['version_id'] = request_data['version']
        request_data['item_id'] = 0
        request_data['project_id'] = project_id
        show_version_name = request_data.get('show_version_name', '')
        # 验证请求参数
        slz = slz_class(data=request.data)
        slz.is_valid(raise_exception=True)
        data = slz.data
        namespace_id = data['namespace_id']

        # 检查是否有命名空间的使用权限
        perm_ctx = NamespaceScopedPermCtx(username=request.user.username,
                                          project_id=project_id,
                                          cluster_id=cluster_id,
                                          name=namespace)
        NamespaceScopedPermission().can_use(perm_ctx)

        config = json.loads(data['config'])
        #  获取关联的应用列表
        version_id = data['version_id']
        version_entity = VersionedEntity.objects.get(id=version_id)

        logger.exception(f"deploy_tag_list {type(data['deploy_tag_list'])}")
        handel_k8s_service_db_config(config,
                                     data['deploy_tag_list'],
                                     version_id,
                                     is_upadte=True)
        resource_version = data['resource_version']
        config['metadata']['resourceVersion'] = resource_version
        cluster_version = get_cluster_version(access_token, project_id,
                                              cluster_id)
        config = handle_k8s_api_version(config, cluster_id, cluster_version,
                                        'Service')
        # 前端的缓存数据储存到备注中
        config = handle_webcache_config(config)

        # 获取上下文信息
        username = request.user.username
        now_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        context = {
            'SYS_CLUSTER_ID': cluster_id,
            'SYS_NAMESPACE': namespace,
            'SYS_VERSION_ID': version_id,
            'SYS_PROJECT_ID': project_id,
            'SYS_OPERATOR': username,
            'SYS_TEMPLATE_ID': version_entity.template_id,
            'SYS_VERSION': show_version_name,
            'LABLE_VERSION': show_version_name,
            'SYS_INSTANCE_ID': data['instance_id'],
            'SYS_CREATOR': data.get('creator', ''),
            'SYS_CREATE_TIME': data.get('create_time', ''),
            'SYS_UPDATOR': username,
            'SYS_UPDATE_TIME': now_time,
        }
        bcs_context = get_bcs_context(access_token, project_id)
        context.update(bcs_context)

        # 生成配置文件
        sys_config = copy.deepcopy(s_sys_con)
        resource_config = update_nested_dict(config, sys_config)
        resource_config = json.dumps(resource_config)
        try:
            config_profile = render_mako_context(resource_config, context)
        except Exception:
            logger.exception(u"配置文件变量替换出错\nconfig:%s\ncontext:%s" %
                             (resource_config, context))
            raise ValidationError(_("配置文件中有未替换的变量"))

        service_name = config.get('metadata', {}).get('name')
        _config_content = {
            'name': service_name,
            'config': json.loads(config_profile),
            'context': context
        }

        # 更新 service
        config_objs = InstanceConfig.objects.filter(
            namespace=namespace_id,
            category=s_cate,
            name=service_name,
        )
        if config_objs.exists():
            config_objs.update(
                creator=username,
                updator=username,
                oper_type='update',
                updated=now_time,
                is_deleted=False,
            )
            _instance_config = config_objs.first()
        else:
            _instance_config = InstanceConfig.objects.create(
                namespace=namespace_id,
                category=s_cate,
                name=service_name,
                config=config_profile,
                instance_id=data.get('instance_id', 0),
                creator=username,
                updator=username,
                oper_type='update',
                updated=now_time,
                is_deleted=False,
            )
        _config_content['instance_config_id'] = _instance_config.id
        configuration = {namespace_id: {s_cate: [_config_content]}}

        driver = get_scheduler_driver(access_token, project_id, configuration,
                                      request.project.kind)
        result = driver.instantiation(is_update=True)

        failed = []
        if isinstance(result, dict):
            failed = result.get('failed') or []
        # 添加操作审计
        activity_client.ContextActivityLogClient(
            project_id=project_id,
            user=username,
            resource_type="instance",
            resource=service_name,
            resource_id=_instance_config.id,
            extra=json.dumps(configuration),
            description=_("更新Service[{}]命名空间[{}]").format(
                service_name, namespace),
        ).log_modify(activity_status="failed" if failed else "succeed")

        if failed:
            return Response({
                "code":
                400,
                "message":
                _("Service[{}]在命名空间[{}]更新失败,请联系集群管理员解决").format(
                    service_name, namespace),
                "data": {},
            })
        return Response({"code": 0, "message": "OK", "data": {}})
Ejemplo n.º 14
0
def can_use_namespace(request, project_id, cluster_id, namespace):
    perm_ctx = NamespaceScopedPermCtx(
        username=request.user.username, project_id=project_id, cluster_id=cluster_id, name=namespace
    )
    NamespaceScopedPermission().can_use(perm_ctx)