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.ResNotFoundError(_("没有查询到实例信息!")) data = details[0] 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"]) ip_used_data = convert_ip_used_data(access_token, project_id, data["cluster_id"], ip_info) render_ip_info = [{ "id": ip, "inner_ip": ip, "unshared": used } for ip, used in ip_used_data.items()] data["ip_info"] = json.dumps(render_ip_info) # 添加release对应的版本及values内容 data.update( self.get_release_info(project_id, data["cluster_id"], namespace_id=data["namespace_id"], namespace=data["namespace"])) return Response(data)
def sync_namespace(self, request, project_id): """同步命名空间 用来同步线上和本地存储的数据,并进行secret等的处理,保证数据一致 """ resp = paas_cc.get_all_clusters(request.user.token.access_token, project_id, desire_all_data=1) if resp.get('code') != ErrorCode.NoError: raise error_codes.APIError( f'get cluster error {resp.get("message")}') data = resp.get('data') or {} results = data.get('results') if not results: raise error_codes.ResNotFoundError( f'not found cluster in project: {project_id}') cluster_id_list = [info['cluster_id'] for info in results] # 触发后台任务进行同步数据 sync_ns_task.delay( request.user.token.access_token, project_id, request.project.project_code, request.project.kind, cluster_id_list, request.user.username, ) return response.Response({'code': 0, 'message': 'task is running'})
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.ResNotFoundError(_("没有查询到实例信息!")) data = details[0] 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"]) nodes_id_ip = self.get_nodes_id_ip(access_token, project_id, data["cluster_id"]) render_ip_info = [] for node_id in ip_info: item = { "id": node_id, "inner_ip": nodes_id_ip[int(node_id)]["inner_ip"], "unshared": ip_info[node_id] } render_ip_info.append(item) data["ip_info"] = json.dumps(render_ip_info) # 添加release对应的版本及values内容 data.update( self.get_release_info(project_id, data["cluster_id"], namespace_id=data["namespace_id"], namespace=data["namespace"])) return Response(data)
def get_metric_info(self, project_id, metric_id): """获取metric信息""" resource = MetricModel.objects.filter(project_id=project_id, pk=metric_id).first() if not resource: raise error_codes.ResNotFoundError(_('metric 不存在')) return resource
def put(self, request, project_id, metric_id): """更新put""" serializer = serializers.UpdateMetricSLZ(data=request.data, context={ 'request': request, 'project_id': project_id }) serializer.is_valid(raise_exception=True) queryset = MetricModel.objects.filter(project_id=project_id, pk=metric_id) ref = queryset.first() if not ref: raise error_codes.ResNotFoundError(_('metric不存在')) # metric_type 不可变,创建是已经申请了dataid,编辑时不能编辑dataid的属性 if ref.metric_type != serializer.data.get('metric_type', ''): raise error_codes.APIError(_('Metric 类型不可更改')) # 校验权限 perm = bcs_perm.Metric(request, project_id, metric_id, ref.name) perm.can_edit(raise_exception=True) # 更新version queryset.update(updator=request.user.username, version=ref.update_version(), **serializer.data) # 异步下发metric tasks.set_metric.delay(request.user.token.access_token, project_id, request.project['kind'], metric_id) return BKAPIResponse({}, message=_('修改metric成功'))
def sync_namespace(self, request, project_id): """同步命名空间 用来同步线上和本地存储的数据,并进行secret等的处理,保证数据一致 """ resp = paas_cc.get_all_clusters(request.user.token.access_token, project_id, desire_all_data=1) if resp.get('code') != ErrorCode.NoError: raise error_codes.APIError( f'get cluster error {resp.get("message")}') data = resp.get('data') or {} results = data.get('results') if not results: raise error_codes.ResNotFoundError( f'not found cluster in project: {project_id}') # 共享集群的命名空间只能通过产品创建,不允许同步 cluster_id_list = [ info['cluster_id'] for info in results if get_cluster_type(info['cluster_id']) != ClusterType.SHARED ] # 触发后台任务进行同步数据 sync_ns_task.delay( request.user.token.access_token, project_id, request.project.project_code, request.project.kind, cluster_id_list, request.user.username, ) request.audit_ctx.update_fields(description=_("同步项目下所有集群的命名空间")) return response.Response({'code': 0, 'message': 'task is running'})
def update(self, id, data): queryset = self.filter(id=id) if not queryset: raise error_codes.ResNotFoundError() # 不允许变动的信息 for key in ['cluster_id', 'region', 'clb_name', 'vpc_id']: data.pop(key, '') data['config'] = json.dumps({ 'network_type': data.pop('network_type'), 'clb_type': data.pop('clb_type'), 'svc_discovery_type': data.pop('svc_discovery_type'), 'clb_project_id': data.pop('clb_project_id'), 'metric_port': data.pop('metric_port'), 'implement_type': data.pop('implement_type'), 'backend_type': data.pop('backend_type'), }) return queryset.update(**data)
def update(self, request, project_id, pk): """ 更新LB配置,包含下面几种场景 1. 增加/减少LB协议类型 2. 增加/减少节点数量(标签+replica) """ serializer = UpdateK8SLoadBalancerSLZ(data=request.data) serializer.is_valid(raise_exception=True) data = serializer.data username = request.user.username data.update({"id": pk, "updator": username}) lb_conf, delete_node_id_list, add_node_id_list = self.get_update_node_info( request, data) # 判断调整的节点是否已经存在,并且是独享的 # self.update_check_node_id(lb_conf, data) # 删除节点配置 if delete_node_id_list: self.delete_node_label(request, delete_node_id_list, project_id, lb_conf) # 添加节点配置 if add_node_id_list: self.add_node_label(request, add_node_id_list, project_id, lb_conf) # 更新lb self.update_lb_conf(lb_conf, data["ip_info"], data["protocol_type"], username) release = self.get_helm_release(lb_conf.cluster_id, lb_conf.name, namespace_id=lb_conf.namespace_id) if not release: raise error_codes.ResNotFoundError(_("没有查询到对应的release信息")) data["namespace_id"] = lb_conf.namespace_id user_log = log_client.ContextActivityLogClient( project_id=project_id, user=request.user.username, resource_type='lb', resource="%s:%s" % (lb_conf.cluster_id, lb_conf.namespace_id), resource_id=pk, extra=json.dumps(data)) # release 对应的版本为"(current-unchanged) v1.1.2" version = data["version"].split( constants.RELEASE_VERSION_PREFIX)[-1].strip() chart_version = self.get_chart_version(project_id, version) updated_instance = release.upgrade_app( access_token=request.user.token.access_token, chart_version_id=chart_version.id, answers=[], customs=[], valuefile=data["values_content"], updator=username) if updated_instance.transitioning_result: user_log.log_modify(activity_status="succeed") return Response() user_log.log_modify(activity_status="failed") raise error_codes.APIError(updated_instance.transitioning_message)
def sync_repo(self, request, project_id_or_code): project_id = request.project.project_id repos = Repository.objects.filter(project_id=project_id) # 同步项目仓库 for info in repos: if info.name != 'public-repo': return self.create(request, project_id, info.id) # 查询不到项目仓库时,返回异常提示 return error_codes.ResNotFoundError(_("没有查询到项目仓库"))
def get_params_for_reupgrade(self, project_id, cluster_id): """获取重新升级的参数 通过升级时记录的参数中直接拿取请求参数 """ log = ClusterInstallLog.objects.filter( oper_type=ClusterOperType.ClusterUpgrade, project_id=project_id, cluster_id=cluster_id ).last() if not log: raise error_codes.ResNotFoundError(_("没有查询到集群的升级记录")) return log.log_params
def list_custom_objects(self, request, project_id, cluster_id, crd_name): cluster_auth = ClusterAuth(request.user.token.access_token, project_id, cluster_id) crd_client = CustomResourceDefinition(cluster_auth) crd = crd_client.get(name=crd_name, is_format=False) if not crd: raise error_codes.ResNotFoundError(_("集群({})中未注册自定义资源({})").format(cluster_id, crd_name)) cobj_client = get_cobj_client_by_crd(cluster_auth, crd_name) cobj_list = cobj_client.list(namespace=request.query_params.get("namespace")) return Response(to_table_format(crd.to_dict(), cobj_list, cluster_id=cluster_id))
def get_cobj_client_by_crd(ctx_cluster: CtxCluster, crd_name: str) -> CustomObject: crd_client = CustomResourceDefinition(ctx_cluster) crd = crd_client.get(name=crd_name, is_format=False) if crd: return CustomObject(ctx_cluster, kind=crd.spec.names.kind, api_version=_get_cobj_api_version(crd)) raise error_codes.ResNotFoundError( _("集群({})中未注册自定义资源({})").format(ctx_cluster.id, crd_name))
def get_chart_version(self, project_id, version): try: chart_version = ChartVersion.objects.get( name=K8S_LB_CHART_NAME, chart__repository__project_id=project_id, version=version, chart__repository__name="public-repo", ) except ChartVersion.DoesNotExist: raise error_codes.ResNotFoundError(_("没有查询到chart版本: {}").format(version)) return chart_version
def get_instance(self, request, project_id, metric_id): """查询Metric实例化的详细信息 """ ref = MetricModel.objects.filter(project_id=project_id, pk=metric_id).first() if not ref: raise error_codes.ResNotFoundError(_('metric不存在')) metric_name = ref.name # 查询项目下的所有集群id列表 access_token = request.user.token.access_token cluster_data = paas_cc.get_all_clusters(access_token, project_id).get('data') or {} cluster_list = cluster_data.get('results') or [] cluster_dict = {} for _n in cluster_list: _env = _n['environment'] if _env in cluster_dict: cluster_dict[_env].append(_n['cluster_id']) else: cluster_dict[_env] = [_n['cluster_id']] # 查询项目下的命名空间列表 access_token = request.user.token.access_token result = paas_cc.get_namespace_list(access_token, project_id, with_lb=0, limit=ALL_LIMIT) ns_list = result.get('data', {}).get('results') or [] ns_dict = {} for _n in ns_list: ns_dict[_n['name']] = _n['id'] if request.project.kind == ProjectKind.MESOS.value: # mesos category_list = ['application', 'deployment'] else: category_list = POD_RES_LIST instance_info = InstanceConfig.objects.filter( is_deleted=False, category__in=category_list).exclude( ins_state=InsState.NO_INS.value) data = [] # 根据集群的环境不同调用不同环境的storageAPI for env, cluster_id_list in cluster_dict.items(): metric_instance_list = get_metric_instances( access_token, project_id, metric_name, env, cluster_id_list, ns_dict, instance_info) data.extend(metric_instance_list) return Response(data)
def __init__(self, request, project_id, resource_id, resource_type=None): super(Cluster, self).__init__(request, project_id, resource_id) if resource_id != NO_RES: cluster = paas_cc.get_cluster(self.access_token, self.project_id, resource_id) if cluster.get('code') != 0: raise error_codes.ResNotFoundError(cluster.get('message', '')) # 通过接口判断资源类型 self.res = cluster['data'] self.resource_name = cluster['data']['name'] else: self.res = None
def get(self, request, project_id, metric_id): """获取metric""" ref = MetricModel.objects.filter(project_id=project_id, pk=metric_id).first() if not ref: raise error_codes.ResNotFoundError(_('metric不存在')) # 校验权限 perm = bcs_perm.Metric(request, project_id, metric_id, ref.name) perm.can_use(raise_exception=True) return BKAPIResponse(ref.to_json(), message=_('获取metric成功'))
def get_namespace_id(access_token, project_id, cluster_ns_name, cluster_id=None): if cluster_id: namespace_list = get_cluster_namespaces(access_token, project_id, cluster_id) else: namespace_list = get_project_namespaces(access_token, project_id) for ns_info in namespace_list: cluster_ns_name_item = (ns_info['cluster_id'], ns_info['name']) if cluster_ns_name == cluster_ns_name_item: return ns_info['id'] raise error_codes.ResNotFoundError(f'not found namespace: {cluster_ns_name}')
def retrieve(self, request): """获取共享chart仓库的信息""" # 因为每个项目下都关联公共仓库,而公共仓库最先存在,因此,取第一个记录 repo = Repository.objects.filter( name=PUBLIC_REPO_NAME).order_by("id").first() if not repo: raise error_codes.ResNotFoundError( _("公共仓库: {}不存在").format(PUBLIC_REPO_NAME)) # 获取仓库的用户名和密码 username, password = repo.username_password return Response({ "url": repo.url, "username": username, "password": password })
def update(self, request, project_id_or_code, cluster_id, ns_name): if ns_name in BCS_RESERVED_NAMESPACES: raise error_codes.ValidateError('不允许更新 BCS 保留的命名空间') # 更新操作审计信息 request.audit_ctx.update_fields(resource_type=ResourceType.Namespace, resource=ns_name) params = self.params_validate(UpdateNamespaceSLZ) ns_client = Namespace(request.ctx_cluster) namespace = ns_client.get(ns_name, is_format=False) if not namespace: raise error_codes.ResNotFoundError('集群 {} 中不存在命名空间 {}'.format(cluster_id, ns_name)) manifest = namespace.data.to_dict() for key in ['labels', 'annotations']: manifest['metadata'][key] = params[key] ns_client.replace(name=ns_name, body=manifest) return Response(manifest)
def retrieve(self, request, project_id_or_code): """获取项目下chart仓库的信息""" # project code 为仓库的名称 repo_name = request.project.project_code # NOTE: 现在一个项目仅有一个私有仓库 try: repo = Repository.objects.get( name=repo_name, project_id=request.project.project_id) except Repository.DoesNotExist: raise error_codes.ResNotFoundError( _("仓库: {}不存在").format(repo_name)) # 获取仓库的用户名和密码 username, password = repo.username_password return Response({ "url": repo.url, "username": username, "password": password })
def scale_instance_resource(username: str, inst_data: InstanceData, ctx_cluster: CtxCluster, show_version: Optional[ShowVersion]): # 针对没有版本控制或者通过非模板集创建的资源进行操作 if not show_version: inst_controller = InstanceController(ctx_cluster, inst_data) inst_controller.scale_resource() return # 通过版本获取资源配置 ns_id = get_namespace_id(ctx_cluster, inst_data.namespace) if not ns_id: raise error_codes.ResNotFoundError( _("集群:{}下命名空间:{}不存在").format(ctx_cluster.id, inst_data.namespace)) instance = get_instance(ns_id, inst_data.name, inst_data.kind) if not instance: raise error_codes.RecordNotFound( _("资源{kind}:{ns_id}:{name}不存在").format(kind=inst_data.kind, ns_id=ns_id, name=inst_data.name)) render_data = VersionInstanceData( instance_id=instance.id, name=inst_data.name, username=username, templateset_id=show_version.template_id, namespace_id=ns_id, version_id=show_version.real_version_id, show_version_id=show_version.id, kind=inst_data.kind, variables=inst_data.variables, ) inst_data.manifest = generate_manifest(ctx_cluster, render_data) inst_controller = InstanceController(ctx_cluster, inst_data) inst_controller.scale_resource() # 更新db中记录 VersionInstance.objects.update_versions( instance_id=instance.instance_id, show_version_name=show_version.name, version_id=show_version.real_version_id, show_version_id=show_version.id, ) InstanceConfig.objects.update_vars_and_configs(instance.id, inst_data.variables, inst_data.manifest)
def retrieve(self, id): queryset = self.filter(id=id) if not queryset: raise error_codes.ResNotFoundError() return queryset[0]
def retrieve_record(self, id): queryset = self.filter(id=id) if not queryset: raise error_codes.ResNotFoundError() return self.parse_record(queryset[0])
def get_custom_resource_definition(self, name): crds = self.list_custom_resource_definition() for crd in crds.items: if crd.metadata.name == name: return crd raise error_codes.ResNotFoundError(f"no crd {name}")
def retrieve(self, request, project_id_or_code, cluster_id, ns_name): namespace = Namespace(request.ctx_cluster).get(ns_name, is_format=False) if not namespace: raise error_codes.ResNotFoundError('集群 {} 中不存在命名空间 {}'.format(cluster_id, ns_name)) return Response(namespace.data.to_dict())