Beispiel #1
0
    def check_resource(self, request, project_id, config, cluster_id,
                       req_instance_num):
        """校验资源是否满足
        """
        conf = config.copy()
        pre_instance_num = int(conf["spec"]["instance"])
        if int(req_instance_num) > pre_instance_num:
            result = paas_cc.get_cluster(request.user.token.access_token,
                                         project_id, cluster_id)
            if result.get("code") != 0:
                raise error_codes.APIError(_("获取资源失败,请联系蓝鲸管理员解决"))

            data = result.get('data') or {}
            remain_cpu = data.get('remain_cpu') or 0
            remain_mem = data.get('remain_mem') or 0

            cpu_require = 0
            mem_require = 0
            # CPU单位是核心,有小数点,内存单位是M,和paas-cc返回一致
            for info in conf["spec"]["template"]["spec"]["containers"]:
                cpu_require += float(info["resources"]["limits"]["cpu"])
                mem_require += float(info["resources"]["limits"]["memory"])
            diff_instance_num = int(req_instance_num) - pre_instance_num
            if remain_cpu < (diff_instance_num * cpu_require):
                raise error_codes.CheckFailed(_("没有足够的CPU资源,请添加node或释放资源!"))
            if remain_mem < (diff_instance_num * mem_require):
                raise error_codes.CheckFailed(_("没有足够的内存资源,请添加node或释放资源!"))
Beispiel #2
0
 def allow_oper_node(self, node_info, curr_node_status):
     not_allow_msg = "some nodes of the selected nodes do not allow operation, please check the nodes status!"
     if node_info['status'] == NodeStatus.ToRemoved and curr_node_status in [
         node_info['status'],
         NodeStatus.Removable,
     ]:
         raise error_codes.CheckFailed(not_allow_msg)
     if node_info['status'] == NodeStatus.Normal and curr_node_status in [node_info['status'], NodeStatus.Normal]:
         raise error_codes.CheckFailed(not_allow_msg)
Beispiel #3
0
def get_application_staff(username, bk_biz_id, fields=None):
    """获取业务的成员列表
    """
    if not fields:
        fields = ["bk_biz_developer", "bk_biz_maintainer", "bk_biz_tester", "bk_biz_productor"]
    resp = get_application_with_page(username, fields=fields, condition={"bk_biz_id": bk_biz_id})
    if resp.get("code") != ErrorCode.NoError:
        raise error_codes.CheckFailed(_("该项目关联的业务不正确,请确认后重试"))
    data = resp.get("data") or {}
    info = data.get("info") or []
    if not info:
        raise error_codes.CheckFailed(_("查询项目信息为空"))
    return info[0]
Beispiel #4
0
    def get_filter_params(self, request):
        """获取过滤参数"""
        cluster_type = request.GET.get("cluster_type")
        if not cluster_type or cluster_type not in constants.CLUSTER_TYPE:
            raise error_codes.CheckFailed(_("集群类型不正确,请确认后重试!"))
        app_status = request.GET.get("app_status")
        if app_status and app_status not in constants.APP_STATUS:
            raise error_codes.CheckFailed(_("应用状态不正确,请确认后重试!"))
        tmpl_set_id = request.GET.get("muster_id")
        app_id = request.GET.get("app_id")
        ns_id = request.GET.get("ns_id")

        return cluster_type, app_status, tmpl_set_id, app_id, ns_id
Beispiel #5
0
 def get_category(self, request, kind):
     """获取类型"""
     category = request.GET.get("category")
     if kind == constants.K8S_KIND:
         if not category:
             raise error_codes.CheckFailed(_("应用类型不能为空"))
         else:
             if category not in constants.CATEGORY_MAP:
                 raise error_codes.CheckFailed(_("类型不正确,请确认"))
             category = [constants.CATEGORY_MAP[category]]
     else:
         category = constants.MESOS_APPLICATION_TYPE
     return category
Beispiel #6
0
 def get_cluster_last_log(self):
     log = ClusterInstallLog.objects.filter(
         project_id=self.project_id, cluster_id=self.cluster_id,
     ).last()
     if not log:
         raise error_codes.CheckFailed(_("没有查询对应的任务日志"))
     return log
Beispiel #7
0
 def get(
     self,
     request,
     project_id,
     all_muster_list,
     muster_id_list,
     category,
     cluster_type,
     app_status,
     app_name,
     ns_id,
     cluster_env_map,
 ):
     if category not in CATEGORY_MAP:
         raise error_codes.CheckFailed(_("类型不正确,请确认"))
     # 获取模板ID和名称的对应关系
     muster_id_name_map = {
         info["id"]: info["name"]
         for info in all_muster_list
     }
     # 获取version instance,用于展示模板集下是否有实例
     muster_num_map = self.get_version_instance(muster_id_list, category,
                                                cluster_type, app_name,
                                                ns_id, cluster_env_map)
     return self.muster_tmpl_handler(muster_id_name_map, muster_num_map)
Beispiel #8
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)
Beispiel #9
0
    def retrieve(self, request, project_id, pk):
        details = self.queryset.filter(id=pk,
                                       project_id=project_id,
                                       is_deleted=False).values()
        if not details:
            raise error_codes.CheckFailed(_("没有查询到实例信息,请联系管理员处理"))
        data = details[0]

        perm = bcs_perm.Namespace(request, project_id, data["namespace_id"])
        perm.can_use(raise_exception=True)

        access_token = request.user.token.access_token
        cluster_id_name_map = self.get_cluster_id_name_map(
            access_token, project_id)
        data["cluster_name"] = cluster_id_name_map[data["cluster_id"]]["name"]
        ip_info = json.loads(data["ip_info"])
        node_id_info_map = self.get_node_info(access_token, project_id,
                                              data["cluster_id"])
        render_ip_info = []
        for info in ip_info:
            item = {
                "id": info,
                "inner_ip": node_id_info_map[int(info)]["inner_ip"],
                "unshared": ip_info[info]
            }
            render_ip_info.append(item)
        data["ip_info"] = json.dumps(render_ip_info)
        return Response(data)
Beispiel #10
0
 def get_params_for_client(self, request):
     name = request.GET.get("name")
     namespace = request.GET.get("namespace")
     category = request.GET.get("category")
     if not (name and namespace and category):
         raise error_codes.CheckFailed(_("参数[name]、[namespace]、[category]不能为空"))
     return name, namespace, category
Beispiel #11
0
    def update(self, request, project_id):
        """更新项目信息"""
        if not self.can_edit(request, project_id):
            raise error_codes.CheckFailed(_("请确认有项目管理员权限,并且项目下无集群"))
        data = self.validate_update_project_data(request)
        access_token = request.user.token.access_token
        data["updator"] = request.user.username

        # 添加操作日志
        ual_client = client.UserActivityLogClient(
            project_id=project_id,
            user=request.user.username,
            resource_type="project",
            resource=request.project.project_name,
            resource_id=project_id,
            description="{}: {}".format(_("更新项目"), request.project.project_name),
        )
        resp = paas_cc.update_project_new(access_token, project_id, data)
        if resp.get("code") != ErrorCode.NoError:
            ual_client.log_modify(activity_status="failed")
            raise error_codes.APIError(_("更新项目信息失败,错误详情: {}").format(resp.get("message")))
        ual_client.log_modify(activity_status="succeed")
        project_data = resp.get("data")
        if project_data:
            project_data["created_at"], project_data["updated_at"] = self.normalize_create_update_time(
                project_data["created_at"], project_data["updated_at"]
            )

        # 主动令缓存失效
        self.invalid_project_cache(project_id)
        # 创建或更新依赖服务,包含data、template、helm
        update_bcs_service_for_project(request, project_id, data)

        return Response(project_data)
Beispiel #12
0
    def update(self, request, project_id):
        """更新项目信息
        """
        if not self.can_edit(request, project_id):
            raise error_codes.CheckFailed("请确认有项目管理员权限,并且项目下无集群", replace=True)
        data = self.validate_update_project_data(request)
        access_token = request.user.token.access_token
        data['updator'] = request.user.username

        # 添加操作日志
        ual_client = client.UserActivityLogClient(
            project_id=project_id,
            user=request.user.username,
            resource_type='project',
            resource=request.project.project_name,
            resource_id=project_id,
            description="更新项目: %s" % request.project.project_name,
        )
        project = paas_cc.update_project_new(access_token, project_id, data)
        if project.get('code') != 0:
            ual_client.log_modify(activity_status='failed')
            raise error_codes.APIError(project.get('message', "更新项目成功"))
        ual_client.log_modify(activity_status='succeed')
        project_data = project.get('data')
        if project_data:
            project_data['created_at'], project_data['updated_at'] = self.normalize_create_update_time(
                project_data['created_at'], project_data['updated_at'])

        # 主动令缓存失效
        self.invalid_project_cache(project_id)
        # 创建或更新依赖服务,包含data、template、helm
        update_bcs_service_for_project(request, project_id, data)

        return Response(project_data)
Beispiel #13
0
 def check_namespace_used(self, cluster_id, namespace_id):
     """校验集群下命名空间是否已经被占用,如果占用则提示已经被使用
     """
     if K8SLoadBlance.objects.filter(cluster_id=cluster_id,
                                     namespace_id=namespace_id,
                                     name=K8S_LB_NAME).exists():
         raise error_codes.CheckFailed(_("命名空间已经被占用,请选择其他命名空间"))
Beispiel #14
0
 def get_instance_info(self, id):
     """获取instance info
     """
     inst_info = InstanceConfig.objects.filter(id=id, is_deleted=False)
     if not inst_info:
         raise error_codes.CheckFailed(_("没有查询到相应的记录"))
     return inst_info
Beispiel #15
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)
Beispiel #16
0
 def get_vpc_id(self, request, region, clb_name):
     data = clb_utils.describe_clb_detail(request.user.token.access_token,
                                          request.user.username,
                                          request.project.cc_app_id, region)
     if clb_name not in data:
         raise error_codes.CheckFailed(f'clb:[{clb_name}] not found')
     return data[clb_name]['vpc_id']
Beispiel #17
0
 def check_node_ip(self):
     project_node_list = [
         info['inner_ip'] for info in self.project_nodes if info['status'] not in [CommonStatus.Removed]
     ]
     intersection = set(project_node_list) & set(self.ip_list)
     if intersection:
         raise error_codes.CheckFailed(_("部分主机已经使用,IP为{}").format(','.join(intersection)))
Beispiel #18
0
    def reinstall(self):
        self.ratelimit()
        # 校验集群编辑权限
        self.check_perm()
        # 通过node id获取Ip信息
        node_info = self.get_node_ip()
        log = self.get_node_last_log()
        node_ip = node_info.get('inner_ip')
        params = json.loads(log.params)
        # 校验权限
        if node_info.get('status') not in [NodeStatus.Removed, NodeStatus.InitialFailed]:
            raise error_codes.CheckFailed(_("IP: {}正在操作中,请勿重复操作").format(node_ip))
        with client.ContextActivityLogClient(
            project_id=self.project_id,
            user=self.username,
            resource_type=ACTIVITY_RESOURCE_TYPE,
            resource=node_ip,
            resource_id=self.node_id,
        ).log_modify():
            self.update_nodes([node_ip])
            # 调用OPS api
            self.need_nat = params['need_nat']
            self.master_ip_list = params['master_ip_list']
            self.module_id_list = params['module_id_list']
            self.ip_list = [node_ip]
            log = self.create_node_by_bcs(
                [node_info], control_ip=params['control_ip'], config=params['config'], websvr=params['websvr']
            )
            if not log.is_finished and log.is_polling:
                log.polling_task()

        return Response({})
Beispiel #19
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)
Beispiel #20
0
def get_application_staff(username, bk_biz_id, fields=None):
    """获取业务的成员列表"""
    if not fields:
        fields = [
            'bk_biz_developer', 'bk_biz_maintainer', 'bk_biz_tester',
            'bk_biz_productor'
        ]
    resp = cmdb.get_application_with_page(username,
                                          fields=fields,
                                          condition={'bk_biz_id': bk_biz_id})
    if resp.get('code') != ErrorCode.NoError:
        raise error_codes.CheckFailed(_('该项目关联的业务不正确,请确认后重试'))
    data = resp.get('data') or {}
    info = data.get('info') or []
    if not info:
        raise error_codes.CheckFailed(_('查询项目信息为空'))
    return info[0]
Beispiel #21
0
 def get_request_category(self, request, project_kind):
     """获取请求类型"""
     category = None
     if project_kind == constants.K8S_KIND:
         category = request.GET.get("category")
         if not category:
             raise error_codes.CheckFailed(_("应用类型不能为空"))
     return category
Beispiel #22
0
 def project_kind(self, request):
     """
     处理项目project info
     """
     kind = request.project.get("kind")
     if kind not in [1, 2]:
         raise error_codes.CheckFailed(_("项目类型必须为k8s/mesos, 请确认后重试!"))
     return kind
Beispiel #23
0
 def node_handler(self, request, project_id, cluster_id, node_info):
     driver = K8SDriver(request, project_id, cluster_id)
     if node_info['status'] == NodeStatus.ToRemoved:
         driver.disable_node(node_info['inner_ip'])
     elif node_info['status'] == NodeStatus.Normal:
         driver.enable_node(node_info['inner_ip'])
     else:
         raise error_codes.CheckFailed(f'node of the {node_info["status"]} does not allow operation')
Beispiel #24
0
 def check_host_stop_scheduler(self, node_info):
     status = [
         NodeStatus.ToRemoved, NodeStatus.Removable,
         NodeStatus.RemoveFailed, CommonStatus.ScheduleFailed,
         NodeStatus.InitialFailed
     ]
     if node_info.get("status") not in status:
         raise error_codes.CheckFailed(_("节点必须要先停用,才可以删除,请确认!"))
Beispiel #25
0
 def get_cluster_by_ns_name(self, request, project_id, ns_name):
     """通过命名空间获取集群"""
     ok, all_ns_info = self.get_namespaces(request, project_id)
     if not ok:
         raise error_codes.APIError.f(all_ns_info.data.get("message"))
     for info in (all_ns_info.get("results") or []):
         if info["name"] == ns_name:
             return info["cluster_id"]
     raise error_codes.CheckFailed(_("没有查询到命名空间对应的集群ID"))
 def validate_instance(self, instance):
     """当instance和ip_list都存在时,要校验两者数量相同"""
     data = self._kwargs.get('data', {})
     ip_list = data.get('ip_list')
     if not ip_list:
         return instance
     if len(ip_list) != instance:
         raise error_codes.CheckFailed(_("参数[ip_list]和[instance]必须相同"))
     return instance
Beispiel #27
0
 def ratelimit(self):
     rate_limiter = RateLimiter(rd_client, '%s_%s' % (self.cluster_id, self.node_id))
     rate_limiter.add_rule(1, {"second": 15})
     try:
         resp = rate_limiter.acquire()
     except Exception as error:
         logger.error('%s, %s' % (bk_error_codes.ConfigError.code, "获取token出现异常,详情:%s" % error))
     if not resp.get('allowed'):
         raise error_codes.CheckFailed(_("已经触发操作,请勿重复操作"))
Beispiel #28
0
    def create_node_labels(self, request, project_id):
        """添加节点标签"""
        # 解析参数
        node_id_list, node_label_info = self.get_create_label_params(request)
        # 校验label中key和value
        self.label_regex(node_label_info)
        # 获取数据库中节点的label
        # NOTE: 节点为正常状态时,才允许设置标签
        project_node_info = self.get_node_list(request, project_id, None).get('results') or []
        if not project_node_info:
            raise error_codes.APIError(_("当前项目下节点为空,请确认"))
        all_node_id_list = []
        all_node_id_ip_map = {}
        for info in project_node_info:
            all_node_id_list.append(info["id"])
            all_node_id_ip_map[info["id"]] = {"inner_ip": info["inner_ip"], "cluster_id": info["cluster_id"]}
            if info['id'] in node_id_list and info['status'] != CommonStatus.Normal:
                raise error_codes.CheckFailed(_("节点不是正常状态时,不允许设置标签"))
        diff_node_id_list = set(node_id_list) - set(all_node_id_list)
        if diff_node_id_list:
            raise error_codes.CheckFailed(_("节点ID [{}] 不属于当前项目,请确认").format(",".join(diff_node_id_list)))
        # 校验权限
        self.check_perm(request, project_id, all_node_id_ip_map, node_id_list)
        # 匹配数据
        pre_node_labels = self.get_labels_by_node(request, project_id, node_id_list)
        label_operation_map = self.get_label_operation(
            pre_node_labels, node_label_info, node_id_list, all_node_id_ip_map
        )
        # k8s 是以节点为维度
        self.create_node_label_via_k8s(request, project_id, label_operation_map)
        # 写入数据库
        self.create_or_update(request, project_id, label_operation_map)

        client.ContextActivityLogClient(
            project_id=project_id,
            user=request.user.username,
            resource_type="node",
            resource=str(node_id_list),
            resource_id=str(node_id_list),
            extra=json.dumps(node_label_info),
            description=_("节点打标签"),
        ).log_add(activity_status="succeed")
        return Response({"code": 0, "message": _("创建成功!")})
    def delete(self, request, project_id, cluster_id, node_id):
        access_token = request.user.token.access_token
        node_info = self.get_node_by_id(access_token, project_id, cluster_id, node_id)
        # check node allow operation
        if node_info.get('status') not in NotReadyNodeStatus:
            raise error_codes.CheckFailed(
                'current node does not allow delete operation, please check node status!')
        # set current node status is removed
        self.update_nodes_in_cluster(
            access_token, project_id, cluster_id, [node_info['inner_ip']], CommonStatus.Removed)

        return response.Response()
Beispiel #30
0
 def get_oper_node_info(self, node_list, req_node_id_list, req_status):
     exist_node_list = []
     for info in node_list:
         curr_node_status = info.get('status')
         info['status'] = req_status
         # check node belong to the cluster and allow to operate
         if info['id'] in req_node_id_list:
             exist_node_list.append(info)
             self.allow_oper_node(info, curr_node_status)
     if len(exist_node_list) != len(req_node_id_list):
         raise error_codes.CheckFailed('many nodes do not belong the cluster')
     return exist_node_list