def create_imagepullsecret(access_token, project_id, project_code, cluster_id, namespace): """先和先前逻辑保持一致 """ dept_auth = { 'auths': create_dept_account(access_token, project_id, project_code, cluster_id) } auth_bytes = bytes(json.dumps(dept_auth), 'utf-8') secret_config = { "apiVersion": "v1", "kind": "Secret", "metadata": { "name": f"{K8S_IMAGE_SECRET_PRFIX}{namespace}", "namespace": namespace }, "data": { ".dockerconfigjson": base64.b64encode(auth_bytes).decode() }, "type": "kubernetes.io/dockerconfigjson" } # client = K8SClient(access_token, project_id, cluster_id, env=None) resp = client.create_secret(namespace, secret_config) if (resp.get('code') != ErrorCode.NoError) and ('already exists' not in resp.get( 'message', '')): raise error_codes.APIError( f'create secret error, {resp.get("message")}')
def rollback_k8sservice(self, ns, cluster_id, spec): client = K8SClient(self.access_token, self.project_id, cluster_id, env=None) name = spec['metadata']['name'] result = client.delete_service(ns, name) if result.get('code') != 0: raise ComponentError(result.get('message', ''))
def get_k8s_context(self, request, project_id_or_code, cluster_id): """获取docker监控信息""" access_token = paas_auth.get_access_token().get("access_token") result = paas_cc.get_project(access_token, project_id_or_code) if result.get("code") != ErrorCode.NoError: raise error_codes.APIError( _("项目Code或者ID不正确: {}").format(result.get("message", ""))) project_id = result["data"]["project_id"] client = K8SClient(access_token, project_id, cluster_id, None) slz = K8SWebConsoleOpenSLZ(data=request.data, context={"client": client}) slz.is_valid(raise_exception=True) try: bcs_context = utils.get_k8s_cluster_context( client, project_id, cluster_id) except Exception as error: logger.exception("get access cluster context failed: %s", error) message = _("获取集群{}【{}】WebConsole session 信息失败").format( cluster_id, cluster_id) # 返回前端消息 raise error_codes.APIError(message) bcs_context["mode"] = k8s.ContainerDirectClient.MODE bcs_context["user_pod_name"] = slz.validated_data["pod_name"] bcs_context["project_id"] = project_id bcs_context.update(slz.validated_data) return bcs_context
def exec_command(access_token: str, project_id: str, cluster_id: str, container_id: str, command: str) -> str: """在k8s容器中执行命令 """ context = {} client = K8SClient(access_token, project_id, cluster_id, None) _context = utils.get_k8s_context(client, container_id) if not _context: raise ValueError(_("container_id不正确或者容器不是运行状态")) context.update(_context) try: bcs_context = utils.get_k8s_cluster_context(client, project_id, cluster_id) except Exception as error: raise ValueError(f'{_("获取集群信息失败, ")}{error}') bcs_context = utils.get_k8s_admin_context(client, bcs_context, WebConsoleMode.INTERNEL.value) bcs_context['user_pod_name'] = context['pod_name'] context.update(bcs_context) client = _k8s_client(context) result = client.exec_command(command) return result
def batch_delete(self, request, project_id, cluster_id): """ 批量删除 ServiceMonitor """ params = self.params_validate(ServiceMonitorBatchDeleteSLZ) svc_monitors = params['service_monitors'] self._validate_namespace_use_perm( project_id, cluster_id, [sm['namespace'] for sm in svc_monitors]) client = K8SClient(request.user.token.access_token, project_id, cluster_id, env=None) for m in svc_monitors: self._single_service_monitor_operate_handler( client.delete_service_monitor, _('删除'), project_id, ActivityType.Delete, m['namespace'], m['name']) metrics_names = ','.join( [f"{sm['namespace']}/{sm['name']}" for sm in svc_monitors]) message = _('删除 Metrics: {} 成功').format(metrics_names) self._activity_log( project_id, request.user.username, metrics_names, message, ActivityType.Delete, ActivityStatus.Succeed, ) return Response({'successes': svc_monitors})
def get_k8s_pod_info(self, request, project_id, cluster_id, ns_name, category_name=None, field=None, pod_name=None): client = K8SClient(request.user.token.access_token, project_id, cluster_id, None) extra_encode = None if category_name: extra = {"data.metadata.ownerReferences.name": category_name} extra_encode = base64_encode_params(extra) field_list = field or [ "resourceName,createTime", "data.status.podIP", "data.status.hostIP", "data.status.phase", "data.status.containerStatuses" ] params = {"namespace": ns_name} if pod_name: params["name"] = pod_name resp = client.get_pod(extra=extra_encode, field=",".join(field_list), params=params) if resp.get("code") != 0: raise error_codes.APIError.f(resp.get("message") or _("查询出现异常"), replace=True) return resp
def list(self, request, project_id, cluster_id): """获取 ServiceMonitor 列表""" cluster_map = self._get_cluster_map(project_id) namespace_map = self._get_namespace_map(project_id) if cluster_id not in cluster_map: raise error_codes.APIError(_('集群 ID {} 不合法').format(cluster_id)) client = K8SClient(request.user.token.access_token, project_id, cluster_id, env=None) manifest = client.list_service_monitor() service_monitors = self._handle_items(cluster_id, cluster_map, namespace_map, manifest) # 共享集群需要再过滤下属于当前项目的命名空间 if get_cluster_type(cluster_id) == ClusterType.SHARED: project_namespaces = get_shared_cluster_proj_namespaces( request.ctx_cluster, request.project.english_name) service_monitors = [ sm for sm in service_monitors if sm['namespace'] in project_namespaces ] for m in service_monitors: m['is_system'] = m['namespace'] in constants.SM_NO_PERM_NAMESPACE m['iam_ns_id'] = calc_iam_ns_id(m['cluster_id'], m['namespace']) return PermsResponse( service_monitors, resource_request=NamespaceRequest(project_id=project_id, cluster_id=cluster_id), )
def get_k8s_category_info(self, request, project_id, cluster_ns_inst, category): """获取分类的上报信息 {'BCS-K8S-15007': {'K8sDeployment': {'inst_list': ['bellke-test-deploy-1'], 'ns_list': ['abc1']}}} """ ret_data = {} for cluster_id, app_info in cluster_ns_inst.items(): client = K8SClient(request.user.token.access_token, project_id, cluster_id, None) curr_func = FUNC_MAP[category] % 'get' resp = getattr(client, curr_func)({'field': ','.join(app_constants.RESOURCE_STATUS_FIELD_LIST)}) if resp.get('code') != ErrorCode.NoError: raise error_codes.APIError.f(resp.get('message')) data = resp.get('data') or [] # TODO: 关于状态匹配可以再根据实际情况进行调整 for info in data: curr_app_id = f'{info["namespace"]}:{info["resourceName"]}' if curr_app_id not in app_info: continue spec = (info.get('data') or {}).get('spec') or {} # 针对不同的模板获取不同的值 replicas, available = utils.get_k8s_desired_ready_instance_count(info, category) curr_key = (cluster_id, info['namespace'], info['resourceName']) ret_data[curr_key] = { 'pod_count': f'{available}/{replicas}', 'build_instance': available, 'instance': replicas, 'status': utils.get_k8s_resource_status(category, info, replicas, available), } if spec.get('paused'): ret_data[curr_key]['status'] = 'Paused' return ret_data
def update_deployment(self, request, project_id, cluster_id, ns, data, kind=2, category=None, app_name=None): """滚动升级 """ if kind == 2: client = MesosClient(request.user.token.access_token, project_id, cluster_id, None) resp = client.update_deployment(ns, data) else: client = K8SClient(request.user.token.access_token, project_id, cluster_id, None) curr_func = getattr(client, FUNC_MAP[category] % "update") resp = curr_func(ns, app_name, data) if resp.get("code") != ErrorCode.NoError: return APIResponse({ "code": resp.get("code", DEFAULT_ERROR_CODE), "message": resp.get("message", _("请求出现异常!")) }) return APIResponse({"message": _("更新成功!")})
def rescheduler_taskgroup(self, request, project_id, cluster_id, ns, instance_name, taskgroup_name, kind=2): """重启更新 """ if kind == 2: client = MesosClient(request.user.token.access_token, project_id, cluster_id, None) resp = client.rescheduler_mesos_taskgroup(ns, instance_name, taskgroup_name) else: client = K8SClient(request.user.token.access_token, project_id, cluster_id, None) resp = client.delete_pod(ns, taskgroup_name) if resp.get("code") != ErrorCode.NoError: return APIResponse({ "code": resp.get("code", DEFAULT_ERROR_CODE), "message": resp.get("message", _("请求出现异常!")) }) return APIResponse({"message": _("重新调度成功!")})
def get_k8s_rs_info(self, request, project_id, cluster_id, ns_name, resource_name): """获取k8s deployment副本信息 """ ret_data = {} client = K8SClient( request.user.token.access_token, project_id, cluster_id, None ) extra = {"data.metadata.ownerReferences.name": resource_name} extra_encode = base64_encode_params(extra) resp = client.get_rs({ "extra": extra_encode, "namespace": ns_name, "field": "resourceName" }) if resp.get("code") != 0: raise error_codes.APIError.f( resp.get("message") or _("查询出现异常"), replace=True ) data = resp.get("data") or [] if not data: return ret_data all_name = [info["resourceName"] for info in data if info.get("resourceName")] return all_name
def update_instance(self, request, project_id, cluster_id, ns, instance_num, conf, kind=2, category=None, name=None): # noqa if kind == 2: client = MesosClient(request.user.token.access_token, project_id, cluster_id, None) resp = client.update_mesos_app_instance(ns, instance_num, conf) else: client = K8SClient(request.user.token.access_token, project_id, cluster_id, None) curr_func = getattr(client, FUNC_MAP[category] % "update") resp = curr_func(ns, name, conf) if resp.get("code") != ErrorCode.NoError: return False, APIResponse({ "code": resp.get("code", DEFAULT_ERROR_CODE), "message": resp.get("message", _("请求出现异常!")) }) return True, APIResponse({"message": _("更新成功!")})
def rollback_k8sdeployment(self, ns, cluster_id, spec): client = K8SClient(self.access_token, self.project_id, cluster_id, env=None) deployment_name = spec['metadata']['name'] client.deep_delete_deployment(ns, deployment_name)
def create_node_label_via_bcs(self, request, project_id, cluster_id, node_id_labels={}): """调用BCS服务创建节点标签 """ client = K8SClient( request.user.token.access_token, project_id, cluster_id, None) node_list = paas_cc.get_node_list( request.user.token.access_token, project_id, cluster_id) if node_list.get("code") != 0: raise error_codes.APIError(_("查询节点失败,请联系管理员处理!")) results = node_list.get("data", {}).get("results", []) if not results: raise error_codes.APIError(_("当前集群下没有节点信息!")) # compose id: ip node_id_ip = { info["id"]: info["inner_ip"] for info in results if str(info["id"]) in node_id_labels.keys() } for node_id, ip in node_id_ip.items(): k8s_resp = client.get_node_detail(ip) if k8s_resp.get("code") != 0: raise error_codes.APIError.f(k8s_resp.get("message"), replace=True) exist_metadata = (k8s_resp.get("data") or {}).get("metadata") or {} exist_labels = exist_metadata.get("labels") or {} if node_id_labels[str(node_id)] == "del": exist_labels.pop("nodetype", None) else: exist_labels.update(K8S_LB_LABEL) exist_labels["$patch"] = "replace" resp = client.create_node_labels(ip, exist_labels) if resp.get("code") != 0: raise error_codes.APIError(_("节点打标签异常,请联系管理员处理!"))
def rollback_k8sstatefulset(self, ns, cluster_id, spec): client = K8SClient(self.access_token, self.project_id, cluster_id, env=None) name = spec['metadata']['name'] client.deep_delete_statefulset(ns, name)
def handler_k8sconfigmap(self, ns, cluster_id, spec): client = K8SClient(self.access_token, self.project_id, cluster_id, env=None) result = client.create_configmap(ns, spec) if result.get('code') != 0: if result.get('code') == 4001: raise ConfigError(_("配置文件格式错误:{}").format(result.get('message'))) raise ComponentError(_("创建K8sConfigMap失败,{}").format(result.get('message')))
def update(self, request, project_id, cluster_id, namespace, name): """ 更新 ServiceMonitor (先删后增) """ params = self.params_validate(ServiceMonitorUpdateSLZ) client = K8SClient(request.user.token.access_token, project_id, cluster_id, env=None) result = self._single_service_monitor_operate_handler( client.get_service_monitor, _('更新'), project_id, ActivityType.Retrieve, namespace, name) manifest = self._update_manifest(result, params) # 更新会合并 selector,因此先删除, 再创建 self._single_service_monitor_operate_handler( client.delete_service_monitor, _('更新'), project_id, ActivityType.Delete, namespace, name) result = self._single_service_monitor_operate_handler( client.create_service_monitor, _('更新'), project_id, ActivityType.Add, namespace, name, manifest, log_success=True, ) return Response(result)
def create_instance(self, request, project_id, cluster_id, ns, data, category="application", kind=2): """创建实例 """ if kind == 2: client = MesosClient(request.user.token.access_token, project_id, cluster_id, None) if category == "application": resp = client.create_application(ns, data) else: resp = client.create_deployment(ns, data) else: client = K8SClient(request.user.token.access_token, project_id, cluster_id, None) curr_func = getattr(client, FUNC_MAP[category] % "create") resp = curr_func(ns, data) if resp.get("code") != ErrorCode.NoError: return APIResponse({ "code": resp.get("code") or DEFAULT_ERROR_CODE, "message": resp.get("message") }) return APIResponse({ "code": resp.get("code", DEFAULT_ERROR_CODE), "message": resp.get("message") })
def online_app_conf(self, request, project_id, project_kind, cluster_id, name, namespace, category): """针对非模板创建的应用,获取线上的配置""" conf = {} client = K8SClient(request.user.token.access_token, project_id, cluster_id, None) curr_func = FUNC_MAP[category] % "get" resp = getattr(client, curr_func)({ "name": name, "namespace": namespace }) if resp.get("code") != 0: raise error_codes.APIError.f( resp.get("message", _("获取应用线上配置异常,请联系管理员处理!"))) data = resp.get("data") or [] if not data: return {} data = data[0] # 组装数据 conf["kind"] = data["resourceType"] conf["metadata"] = {} conf["spec"] = data["data"]["spec"] conf["metadata"]["name"] = data["data"]["metadata"]["name"] conf["metadata"]["namespace"] = data["data"]["metadata"]["namespace"] conf["metadata"]["labels"] = data["data"]["metadata"]["labels"] conf["metadata"]["annotations"] = data["data"]["metadata"][ "annotations"] return conf
def get_k8s_app_deploy_with_post(self, request, project_id, cluster_id, instance_name=None, category="application", namespace=None, field=None): """获取k8s下application和deployment状态 """ client = K8SClient(request.user.token.access_token, project_id, cluster_id, None) curr_func = getattr(client, "%s_with_post" % (FUNC_MAP[category] % "get")) params = { "name": instance_name, "namespace": namespace, "field": ",".join(field) } resp = curr_func(params) if resp.get("code") != ErrorCode.NoError: return False, APIResponse({ "code": resp.get("code") or DEFAULT_ERROR_CODE, "message": resp.get("message") }) return True, resp
def register_default_ns(access_token, username, project_id, project_code, cluster_id): """注册默认的命名空间(针对k8s集群) 1. 创建存储镜像账号的secret 2. 将 default 命名空间注册到paas_cc 上 project_code = request.project.english_name """ # 组装创建ns的数据 data = {'env_type': 'dev', 'name': 'default', 'cluster_id': cluster_id} ns_base = NamespaceBase() # 1. 创建存储镜像账号的secret client = K8SClient(access_token, project_id, data['cluster_id'], env=None) ns_base.create_jfrog_secret(client, access_token, project_id, project_code, data) # 2. 将 default 命名空间注册到paas_cc 上 result = paas_cc.create_namespace(access_token, project_id, data['cluster_id'], data['name'], None, username, data['env_type']) if result.get('code') != 0: if 'Duplicate entry' in result.get('message', ''): message = _("创建失败,namespace名称已经在其他项目存在") else: message = result.get('message', '') return False, message # 注册资源到权限中心 request = RequestClass(username=username, access_token=access_token, project_code=project_code) perm = bcs_perm.Namespace(request, project_id, bcs_perm.NO_RES, data['cluster_id']) perm.register(str(result['data']['id']), result['data']['name']) return True, _("命名空间[default]注册成功")
def scale_instance(self, request, project_id, cluster_id, ns, app_name, instance_num, kind=2, category=None, data=None): # noqa """扩缩容 """ if kind == 2: client = MesosClient(request.user.token.access_token, project_id, cluster_id, None) resp = client.scale_mesos_app_instance(ns, app_name, instance_num) else: client = K8SClient(request.user.token.access_token, project_id, cluster_id, None) data["spec"]["replicas"] = int(instance_num) curr_func = getattr(client, FUNC_MAP[category] % "update") resp = curr_func(ns, app_name, data) if resp.get("code") != ErrorCode.NoError: return APIResponse({ "code": resp.get("code", DEFAULT_ERROR_CODE), "message": resp.get("message", _("请求出现异常!")) }) return APIResponse({"message": _("更新成功!")})
def get_k8s_context(self, request, project_id, cluster_id): """获取k8s的上下文信息""" client = K8SClient(request.user.token.access_token, project_id, cluster_id, None) try: bcs_context = utils.get_k8s_cluster_context( client, project_id, cluster_id) except Exception as error: logger.exception("get access cluster context failed: %s", error) message = _("获取集群{}【{}】WebConsole 信息失败").format( self.cluster_name, cluster_id) # 记录操作日志 utils.activity_log(project_id, cluster_id, self.cluster_name, request.user.username, False, message) # 返回前端消息 raise error_codes.APIError( _("{},请检查 Deployment【kube-system/bcs-agent】是否正常{}").format( message, settings.COMMON_EXCEPTION_MSG)) if request.GET.get("container_id"): bcs_context = self.get_k8s_container_context( request, project_id, cluster_id, client, bcs_context) else: bcs_context = self.get_k8s_cluster_context(request, project_id, cluster_id, client, bcs_context) return bcs_context
def resume_update_deployment(self, request, project_id, cluster_id, ns, deployment_name, kind=2, category=None): """重启更新 """ if kind == 2: client = MesosClient(request.user.token.access_token, project_id, cluster_id, None) resp = client.resume_update_deployment(ns, deployment_name) else: client = K8SClient(request.user.token.access_token, project_id, cluster_id, None) curr_func = getattr(client, FUNC_MAP[category] % "patch") params = {"spec": {"paused": False}} resp = curr_func(ns, deployment_name, params) if resp.get("code") != ErrorCode.NoError: return APIResponse({ "code": resp.get("code", DEFAULT_ERROR_CODE), "message": resp.get("message", _("请求出现异常!")) }) return APIResponse({"message": _("重启更新成功!")})
def get_k8s_rs_info(self, request, project_id, cluster_id, ns_name, resource_name): """获取k8s deployment副本信息""" ret_data = {} client = K8SClient(request.user.token.access_token, project_id, cluster_id, None) extra = {"data.metadata.ownerReferences.name": resource_name} extra_encode = base64_encode_params(extra) resp = client.get_rs({ "extra": extra_encode, "namespace": ns_name, "field": "resourceName,data.status" }) if resp.get("code") != 0: raise error_codes.APIError.f(resp.get("message") or _("查询出现异常"), replace=True) data = resp.get("data") or [] if not data: return ret_data # NOTE: 因为线上存在revision history,需要忽略掉replica为0的rs rs_name_list = [ info["resourceName"] for info in data if info.get("resourceName") and getitems(info, ["data", "status", "replicas"], 0) > 0 ] return rs_name_list
def delete_instance( self, request, project_id, cluster_id, ns, instance_name, category="application", kind=2, inst_id_list=None, enforce=0, ): """删除instance""" if kind == 2: client = MesosClient(request.user.token.access_token, project_id, cluster_id, None) if category == "application": resp = client.delete_mesos_app_instance(ns, instance_name, enforce=enforce) elif category == "deployment": resp = client.delete_deployment(ns, instance_name, enforce=enforce) elif category == "secret": resp = client.delete_secret(ns, instance_name) elif category == "configmap": resp = client.delete_configmap(ns, instance_name) else: resp = client.delete_service(ns, instance_name) if inst_id_list: delete_instance_task.delay(request.user.token.access_token, inst_id_list, kind) else: client = K8SClient(request.user.token.access_token, project_id, cluster_id, None) # deployment 需要级联删除 res\pod; daemonset/job/statefulset 需要级联删除 pod if FUNC_MAP[category] in ['%s_deployment', '%s_daemonset', '%s_job', '%s_statefulset']: fun_prefix = 'deep_delete' else: fun_prefix = 'delete' curr_func = getattr(client, FUNC_MAP[category] % fun_prefix) resp = curr_func(ns, instance_name) # 级联删除,会返回空 if resp is None: # 启动后台任务,轮训任务状态 if inst_id_list: delete_instance_task.delay(request.user.token.access_token, inst_id_list, kind) return APIResponse({"code": ErrorCode.NoError, "message": _("删除成功")}) # response msg = resp.get("message") # message中有not found或者node does not exist时,认为已经删除成功 # 状态码为正常或者满足不存在条件时,认为已经删除成功 if ( ( resp.get("code") in [ErrorCode.NoError, ErrorCode.MesosDeploymentNotFound, ErrorCode.MesosApplicationNotFound] ) or ("not found" in msg) or ("node does not exist" in msg) ): return APIResponse({"code": ErrorCode.NoError, "message": _("删除成功")}) return APIResponse({"code": resp.get("code"), "message": msg})
def handler_update_k8sconfigmap(self, ns, cluster_id, spec): client = K8SClient(self.access_token, self.project_id, cluster_id, env=None) name = spec['metadata']['name'] result = client.update_configmap(ns, name, spec) if result.get('code') != 0: if result.get('code') == 4001: raise ConfigError(_("配置文件格式错误:{}").format(result.get('message'))) raise ComponentError(_("更新K8sConfigMap失败,{}").format(result.get('message')))
def handler_update_k8sstatefulset(self, ns, cluster_id, spec): client = K8SClient(self.access_token, self.project_id, cluster_id, env=None) deployment_name = spec['metadata']['name'] result = client.update_statefulset(ns, deployment_name, spec) if result.get('code') != 0: if result.get('code') == 4001: raise ConfigError(_("配置文件格式错误:{}").format(result.get('message'))) raise ComponentError(_("更新K8sStatefulSet失败,{}").format(result.get('message')))
def get_k8s_context(self, request, project_id, cluster_id): """获取docker监控信息 """ client = K8SClient(request.user.token.access_token, project_id, cluster_id, None) slz = K8SWebConsoleSLZ(data=request.query_params, context={'client': client}) slz.is_valid(raise_exception=True) try: bcs_context = utils.get_k8s_cluster_context(client, project_id, cluster_id) except Exception as error: logger.exception("get access cluster context failed: %s", error) message = f"获取集群{self.cluster_name}【{cluster_id}】WebConsole 信息失败" # 记录操作日志 utils.activity_log(project_id, self.cluster_name, request.user.username, False, message) # 返回前端消息 raise error_codes.APIError( f"{message},请检查 Deployment【kube-system/bcs-agent】是否正常{settings.COMMON_EXCEPTION_MSG}") # kubectl版本区别 _, version = get_cluster_proper_kubectl(request.user.token.access_token, project_id, cluster_id) kubectld_version = get_kubectld_version(version) container_id = slz.validated_data.get('container_id') if container_id: bcs_context['mode'] = k8s.ContainerDirectClient.MODE bcs_context['user_pod_name'] = slz.validated_data['pod_name'] bcs_context.update(slz.validated_data) else: bcs_context = utils.get_k8s_admin_context(client, bcs_context, settings.WEB_CONSOLE_MODE) ctx = {'username': self.request.user.username, 'settings': settings, 'kubectld_version': kubectld_version, 'namespace': constants.NAMESPACE, 'pod_spec': utils.get_k8s_pod_spec(client), 'username_slug': utils.get_username_slug(self.request.user.username), # 缓存ctx, 清理使用 'should_cache_ctx': True} ctx.update(bcs_context) try: pod_life_cycle.ensure_namespace(ctx) configmap = pod_life_cycle.ensure_configmap(ctx) logger.debug('get configmap %s', configmap) pod = pod_life_cycle.ensure_pod(ctx) logger.debug('get pod %s', pod) except pod_life_cycle.PodLifeError as error: logger.error("kubetctl apply error: %s", error) utils.activity_log(project_id, self.cluster_name, request.user.username, False, '%s' % error) raise error_codes.APIError('%s' % error) except Exception as error: logger.exception("kubetctl apply error: %s", error) utils.activity_log(project_id, self.cluster_name, request.user.username, False, "申请pod资源失败") raise error_codes.APIError(f"申请pod资源失败,请稍后再试{settings.COMMON_EXCEPTION_MSG}") bcs_context['user_pod_name'] = pod.metadata.name return bcs_context
def list(self, request, project_id, cluster_id): """ 获取可选 Service 列表""" client = K8SClient(request.user.token.access_token, project_id, cluster_id, env=None) resp = client.get_service({'env': 'k8s'}) response_data = self._slim_down_service(resp.get('data') or []) return Response(response_data)