def get(self, request, project_id): """ 获取项目下所有的secrets """ # 获取kind flag, project_kind = self.get_project_kind(request, project_id) if not flag: return project_kind cluster_dicts = self.get_project_cluster_info(request, project_id) cluster_data = cluster_dicts.get('results', {}) or {} data = [] params = dict(request.GET.items()) s_cate = 'secret' if project_kind == MESOS_VALUE else 'K8sSecret' access_token = request.user.token.access_token is_decode = request.GET.get('decode') is_decode = True if is_decode == '1' else False # get project namespace info namespace_dict = app_utils.get_ns_id_map( request.user.token.access_token, project_id) for cluster_info in cluster_data: cluster_id = cluster_info.get('cluster_id') # 当参数中集群ID存在时,判断集群ID匹配成功后,继续后续逻辑 if params.get('cluster_id') and params['cluster_id'] != cluster_id: continue cluster_env = cluster_info.get('environment') code, cluster_secrets = self.get_secrets_by_cluster_id( request, params, project_id, cluster_id, project_kind=project_kind) # 单个集群错误时,不抛出异常信息 if code != ErrorCode.NoError: continue self.handle_data(request, cluster_secrets, project_kind, s_cate, access_token, project_id, cluster_id, is_decode, cluster_env, cluster_info.get('name', ''), namespace_dict=namespace_dict) data += cluster_secrets # 按时间倒序排列 data.sort(key=lambda x: x.get('createTime', ''), reverse=True) return APIResponse({ "code": ErrorCode.NoError, "data": { "data": data, "length": len(data) }, "message": "ok" })
def get(self, request, project_id): """获取所有的命名空间 """ kind = self.project_kind(request) cluster_type, category = self.get_cluster_category(request, kind) all_namespaces = self.get_all_namespace(request, project_id) cluster_env_map = self.get_cluster_id_env(request, project_id) ret_data = self.compose_data(all_namespaces, cluster_env_map, cluster_type) return APIResponse({"data": ret_data})
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 query_events(self, request, project_id, cluster_id, params): """查询事件 """ client = BCSDriver(request, project_id, cluster_id) resp = client.get_events(params) if resp.get("code") != ErrorCode.NoError: return APIResponse({ "code": resp.get("code", DEFAULT_ERROR_CODE), "message": resp.get("message", _("请求出现异常!")) }) return APIResponse({ "data": { "data": resp.get("data", []), "total": 100 if resp.get("total", 0) > 100 else resp.get("total", 0) } })
def get_namespace_info(self, request, project_id, ns_id): """获取单个namespace """ resp = paas_cc.get_namespace( request.user.token.access_token, project_id, ns_id ) if resp.get("code") != ErrorCode.NoError: return False, APIResponse({ "code": resp.get("code") or DEFAULT_ERROR_CODE, "message": resp.get("message") }) if not resp.get("data"): return False, APIResponse({ "code": 400, "message": _("查询记录为空!") }) return True, resp["data"]
def cancel_update_deployment(self, request, project_id, cluster_id, ns, deployment_name, kind=2): """取消更新 """ if kind == 2: client = MesosClient( request.user.token.access_token, project_id, cluster_id, None ) resp = client.cancel_update_deployment(ns, deployment_name) else: resp = DEFAULT_RESPONSE if resp.get("code") != ErrorCode.NoError: return APIResponse({ "code": resp.get("code", DEFAULT_ERROR_CODE), "message": resp.get("message", _("请求出现异常!")) }) return APIResponse({ "message": _("取消更新成功!") })
def get_instances(self, request, project_id, cluster_id, kind=2): """拉取项目下的所有Instance""" if kind == 2: client = MesosClient(request.user.token.access_token, project_id, cluster_id, None) resp = client.get_mesos_app_instances() else: resp = DEFAULT_RESPONSE if resp.get("code") != ErrorCode.NoError: return False, APIResponse({"code": resp.get("code", DEFAULT_ERROR_CODE), "message": resp.get("message")}) return True, resp["data"]
def get_project_kind(self, request, project_id): """获取项目类型,现阶段包含mesos和k8s""" project_info = paas_cc.get_project(request.user.token.access_token, project_id) if project_info.get("code") != ErrorCode.NoError: return False, APIResponse({ "code": project_info.get("code", DEFAULT_ERROR_CODE), "message": _("请求出现异常!") }) if project_info.get("data", {}).get("kind") not in constants.PROJECT_KIND_LIST: return False, APIResponse({ "code": ErrorCode.UserError, "message": _("该项目编排类型不正确!"), "data": None }) return True, project_info["data"]["kind"]
def get_pod_or_taskgroup(self, request, project_id, cluster_id, field=None, app_name=None, taskgroup_name=None, ns_name=None, kind=2, category=None): """获取taskgroup或者pod """ if kind == 2: client = MesosClient(request.user.token.access_token, project_id, cluster_id, None) resp = client.get_mesos_app_taskgroup( field=field or "data.containerStatuses.containerID,namespace,data.rcname", app_name=app_name, taskgroup_name=taskgroup_name, namespace=ns_name, ) else: if taskgroup_name: pod_name = taskgroup_name rs_name = None elif app_name: pod_name = None rs_name = app_name if category in ["deployment", "K8sDeployment"]: rs_name = self.get_k8s_rs_info(request, project_id, cluster_id, ns_name, app_name) if not rs_name: return True, [] else: pod_name = None rs_name = None resp = self.get_k8s_pod_info(request, project_id, cluster_id, ns_name, category_name=rs_name, field=field, pod_name=pod_name) if resp.get("code") != ErrorCode.NoError: return False, APIResponse({ "code": resp.get("code", DEFAULT_ERROR_CODE), "message": resp.get("message") }) return True, resp["data"]
def get_project_clusters(self, request, project_id): """查询项目下所有的集群""" resp = paas_cc.get_all_clusters(request.user.token.access_token, project_id, limit=1000, offset=0) if resp.get("code") != ErrorCode.NoError: return False, APIResponse({"code": resp.get("code", DEFAULT_ERROR_CODE), "message": resp.get("message")}) # 获取集群id list cluster_id_list = [] data = resp.get("data") or {} for info in data.get("results") or []: cluster_id_list.append(info["cluster_id"]) return True, cluster_id_list
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 = retry_requests(curr_func, params=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 get(self, request, project_id): """获取项目下的所有Ingress """ project_kind = request.project.kind project_kind_name = ClusterType.get(project_kind) if project_kind_name != 'Kubernetes': raise error_codes.CheckFailed.f("K8S项目才有Ingress", replace=True) cluster_dicts = self.get_project_cluster_info(request, project_id) cluster_data = cluster_dicts.get('results', {}) or {} # 获取命名空间的id namespace_dict = app_utils.get_ns_id_map( request.user.token.access_token, project_id) s_cate = 'K8sIngress' is_decode = False params = {} access_token = request.user.token.access_token data = [] for cluster_info in cluster_data: cluster_id = cluster_info.get('cluster_id') cluster_env = cluster_info.get('environment') code, cluster_data = self.get_ingress_by_cluser_id( request, params, project_id, cluster_id) # 单个集群错误时,不抛出异常信息 if code != ErrorCode.NoError: continue self.handle_data(request, cluster_data, project_kind, s_cate, access_token, project_id, cluster_id, is_decode, cluster_env, cluster_info.get('name', ''), namespace_dict=namespace_dict) data += cluster_data # 按时间倒序排列 data.sort(key=lambda x: x.get('createTime', ''), reverse=True) return APIResponse({ "code": ErrorCode.NoError, "data": { "data": data, "length": len(data) }, "message": "ok" })
def get(self, request, project_id, muster_id): """获取命名空间 """ # 获取参数 group_by = request.GET.get('group_by') or "env_type" category = request.GET.get("category") show_version_name = request.GET.get('show_version_name') res_name = request.GET.get('res_name') perm_can_use = request.GET.get('perm_can_use') if perm_can_use == '1': perm_can_use = True else: perm_can_use = False # 前端的category转换为后台需要的类型 if category != 'ALL': project_kind = request.project.kind category = get_real_category(project_kind, category) if category != 'ALL' and category not in MODULE_DICT: raise error_codes.CheckFailed.f(u"category: %s 不存在" % category) # 获取被占用的ns,没有处于删除中和已删除 ns_id_list = self.get_active_ns( muster_id, show_version_name, category, res_name) # 查询ns信息 results = self.get_ns_info(request, project_id, ns_id_list) # 解析&排序 cluster_env_map = self.get_cluster_env_map(request, project_id) results = filter(lambda x: x["id"] in ns_id_list, results) results = [{'name': k, 'cluster_name': cluster_env_map.get(k, {}).get('cluster_name', k), 'environment_name': "正式" if cluster_env_map.get(k, {}).get( 'cluster_env_str', '') == 'prod' else "测试", 'results': sorted( list(v), key=lambda x: x['id'], reverse=True)} for k, v in groupby(sorted(results, key=lambda x: x[group_by]), key=lambda x: x[group_by])] # ordering = [i.value for i in constants.EnvType] # results = sorted(results, key=lambda x: ordering.index(x['name'])) ret_data = [] for info in results: for item in (info["results"] or []): item["muster_id"] = muster_id item["environment"] = cluster_env_map.get(item["cluster_id"], {}).get("cluster_env_str") info["results"] = self.bcs_perm_handler( request, project_id, info["results"], filter_use=perm_can_use, ns_id_flag="id", ns_name_flag="name" ) if info["results"]: ret_data.append(info) return APIResponse({ "data": ret_data })
def get(self, request, project_id): cluster_type, app_status, tmpl_set_id, app_id, ns_id = self.get_filter_params(request, project_id) project_kind = self.project_kind(request) # 获取模板集 all_tmpl_set_list = self.get_filter_tmpl_set(project_id, tmpl_set_id) # 获取实例名称 app_name = self.get_inst_name(app_id) # 获取模板 category = self.get_request_category(request, project_kind) tmpl_info, newest_version_tmpl = self.get_template(project_kind, all_tmpl_set_list, category) print(app_name, tmpl_info, newest_version_tmpl) return APIResponse({"data": {}})
def destroy(self, request, project_id, pk): """删除nginx ingress 1. 标识LB配置 2. 删除节点标签nodetype 3. 删除helm记录 """ lb_conf = self.get_object() perm = bcs_perm.Namespace(request, project_id, lb_conf.namespace_id) perm.can_use(raise_exception=True) # 标识LB被删除 self.delete_lb_conf(lb_conf) # 删除节点标签 delete_node_id_list = [ node_id for node_id in json.loads(lb_conf.ip_info) ] self.delete_node_label(request, delete_node_id_list, project_id, lb_conf) # 删除helm app_instance = self.get_k8s_bcs_app(lb_conf.namespace_id, self.chart_info) if not app_instance: return APIResponse({"message": _("删除成功")}) 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) app_instance.destroy(username=request.user.username, access_token=request.user.token.access_token) # 因为是helm中是异步过程,因此,放到后台处理 # if App.objects.filter(id=app_instance.id).exists(): # user_log.log_delete(activity_status="failed") # return APIResponse({"code": 400, "message": app_instance.transitioning_message}) user_log.log_delete(activity_status="succeed") return APIResponse({"message": _("任务下发成功!")})
def get_namespaces(self, request, project_id): """获取namespace """ resp = paas_cc.get_namespace_list( request.user.token.access_token, project_id, limit=10000, offset=0 ) if resp.get("code") != ErrorCode.NoError: return False, APIResponse({ "code": resp.get("code", DEFAULT_ERROR_CODE), "message": resp.get("message") }) return True, resp["data"]
def get(self, request, project_id): """获取所有实例 """ kind = self.project_kind(request) cluster_type, category = self.get_cluster_category(request, kind) all_musters = self.get_muster(project_id) version_inst_map = self.get_version_instances(all_musters.keys()) version_inst_cluster = self.get_insts(version_inst_map.keys(), category=category) cluster_env_map = self.get_cluster_id_env(request, project_id) # 组装返回数据 ret_data = self.compose_data(version_inst_cluster, cluster_env_map, cluster_type) ret_data = [{"app_id": val, "app_name": key} for key, val in ret_data.items()] return APIResponse({"data": ret_data})
def get_taskgroup(self, request, project_id, lb_id): # 判断 lb 的状态 validate_res, validate_msg = self.validate_lb(request, project_id, lb_id, "get_taskgroup", is_check_use=False) if not validate_res: return Response(validate_msg) # 获取kind flag, project_kind = self.get_project_kind(request, project_id) if not flag: return project_kind # 根据 lb 获取 Deployment的信息 name = self.lb_data.get("name") cluster_id = self.lb_data.get('cluster_id') data_dict = self.lb_data.get('data_dict') # 查询 namespace if data_dict: data_dict = json.loads(data_dict) else: data_dict = {} namespace = get_namespace_name(request.user.token.access_token, project_id, data_dict) # 获取taskagroup或者group field = self.get_filed(project_kind) rc_names = self.get_rc_name_by_deployment_base( request, project_id, cluster_id, name, project_kind=project_kind, namespace=namespace) rc_names = list(set(rc_names)) or ["None"] flag, resp = self.get_pod_or_taskgroup( request, project_id, cluster_id, field=field, app_name=",".join(rc_names), ns_name=namespace, ) if not flag: return resp if project_kind == 2: ret_data = self.get_task_group_info_base(resp, namespace=namespace) else: ret_data = [] # 处理数据方便前台使用 return APIResponse({"data": ret_data})
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 get(self, request, project_id): """查询项目下不同集群类型的模板集 """ flag, kind = self.get_project_kind(request, project_id) if not flag: return kind cluster_type, category = self.get_cluster_category(request, kind) all_musters = self.get_muster(project_id) version_inst_map = self.get_version_instances(all_musters.keys()) version_inst_cluster = self.get_insts(version_inst_map.keys(), category=category) cluster_env_map = self.get_cluster_id_env(request, project_id) # 组装数据 ret_data = self.compose_data( all_musters, version_inst_map, version_inst_cluster, cluster_env_map, cluster_type) ret_data = [{"muster_id": key, "muster_name": val} for key, val in ret_data.items()] return APIResponse({"data": ret_data})
def get(self, request, project_id): """ 获取项目下所有的ConfigMap """ # 获取kind project_kind = request.project.kind if project_kind not in [info[0] for info in constants.ProjectKind.get_choices()]: raise error_codes.CheckFailed(_("项目编排类型不正确")) cluster_dicts = self.get_project_cluster_info(request, project_id) cluster_data = cluster_dicts.get('results', {}) or {} data = [] params = dict(request.GET.items()) s_cate = 'configmap' if project_kind == MESOS_VALUE else 'K8sConfigMap' access_token = request.user.token.access_token is_decode = request.GET.get('decode') is_decode = True if is_decode == '1' else False # get project namespace info namespace_dict = app_utils.get_ns_id_map(access_token, project_id) for cluster_info in cluster_data: cluster_id = cluster_info.get('cluster_id') # 当参数中集群ID存在时,判断集群ID匹配成功后,继续后续逻辑 if params.get('cluster_id') and params['cluster_id'] != cluster_id: continue cluster_env = cluster_info.get('environment') code, cluster_configmaps = self.get_configmaps_by_cluster_id( request, params, project_id, cluster_id, project_kind=project_kind) # 单个集群错误时,不抛出异常信息 if code != ErrorCode.NoError: continue self.handle_data(request, cluster_configmaps, project_kind, s_cate, access_token, project_id, cluster_id, is_decode, cluster_env, cluster_info.get('name', ''), namespace_dict=namespace_dict) data += cluster_configmaps # 按时间倒序排列 data.sort(key=lambda x: x.get('createTime', ''), reverse=True) return APIResponse({ "code": ErrorCode.NoError, "data": { "data": data, "length": len(data) }, "message": "ok" })
def get_mesos_app_deploy_with_post(self, request, project_id, cluster_id, instance_name=None, category="application", field=None, namespace=None): """查询mesos下application和deployment的状态""" client = MesosClient(request.user.token.access_token, project_id, cluster_id, None) if category == "application": resp = retry_requests( client.get_application_with_post, data={ "name": instance_name, "field": field or "data.metadata.name,data.metadata.namespace,data.status,data.message", "namespace": namespace, }, ) else: resp = retry_requests( client.get_deployment_with_post, data={ "name": instance_name, "field": field or "data.metadata.name,data.metadata.namespace,data.status,data.message", "namespace": namespace, }, ) 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 list(self, request, project_id, cluster_id): used_ns_id_list = K8SLoadBlance.objects.filter( project_id=project_id, cluster_id=cluster_id, is_deleted=False).values("namespace_id") return APIResponse( {"data": [info["namespace_id"] for info in used_ns_id_list]})
def update(self, request, project_id, pk): """ 更新LB配置,包含下面几种场景 1. 增加/减少LB协议类型 2. 增加/减少节点数量(标签+replica) """ req_data = dict(request.data) req_data.update({"id": pk, "updator": request.user.username}) serializer = NginxIngressUpdateSLZ(data=req_data) serializer.is_valid(raise_exception=True) data = serializer.data lb_conf, delete_node_id_list, add_node_id_list = self.get_update_node_info( request, data) perm = bcs_perm.Namespace(request, project_id, lb_conf.namespace_id) perm.can_use(raise_exception=True) # 判断调整的节点是否已经存在,并且是独享的 # 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"], request.user.username) app_instance = self.get_k8s_bcs_app(lb_conf.namespace_id, self.chart_info) if not app_instance: return APIResponse({"code": 400, "message": _("没有查询到应用信息")}) data["namespace_id"] = lb_conf.namespace_id namespace_info = self.get_ns_info(request, data["namespace_id"]) valuefile = self.render_yaml(request.user.token.access_token, project_id, lb_conf.cluster_id, data, namespace_info) 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)) updated_instance = app_instance.upgrade_app( access_token=request.user.token.access_token, chart_version_id=self.chart_version.id, answers=[], customs=[], valuefile=valuefile, updator=request.user.username) if updated_instance.transitioning_result: user_log.log_modify(activity_status="succeed") return APIResponse({"message": "更新成功!"}) user_log.log_modify(activity_status="failed") return APIResponse({ "code": 400, "message": updated_instance.transitioning_message })
def create(self, request, project_id): """针对nginx的实例化,主要有下面几步: 1. 存储用户设置的配置 2. 根据用户选择的节点打标签 3. 根据透露给用户的选择,渲染values.yaml文件 4. 实例化controller相关配置 """ data = dict(request.data) data.update({ "project_id": project_id, "creator": request.user.username, "updator": request.user.username, "name": K8S_LB_NAME }) ns_id = data['namespace_id'] # 检查命名空间是否被占用 self.check_namespace_used(data['cluster_id'], ns_id) perm = bcs_perm.Namespace(request, project_id, ns_id) perm.can_use(raise_exception=True) # 检查节点ID是否已经存在,不允许占用独享的节点 # ip_info = json.loads(data["ip_info"]) # self.check_used_node(ip_info.keys()) value_file_content, namespace_info = self.pre_create(request, data) user_log = log_client.ContextActivityLogClient( project_id=project_id, user=request.user.username, resource_type='lb', resource="%s:%s" % (data["cluster_id"], data["namespace_id"]), extra=json.dumps(data)) # 4. helm apply try: helm_app_info = App.objects.initialize_app( access_token=request.user.token.access_token, name=K8S_LB_NAME, project_id=project_id, cluster_id=data["cluster_id"], namespace_id=data["namespace_id"], namespace=namespace_info["name"], chart_version=self.chart_version, answers=[], customs=[], valuefile=value_file_content, creator=request.user.username, updator=request.user.username) except Exception as err: logger.exception('Create helm app error, detail: %s' % err) helm_app_info = None if helm_app_info: if helm_app_info.transitioning_result: user_log.log_add(activity_status="succeed") return APIResponse({"message": _("创建成功!")}) else: user_log.log_add(activity_status="failed") raise error_codes.CheckFailed(_("创建失败,请查看实例详情!")) else: # 5. 如果失败删除k8s lb实例 K8SLoadBlance.objects.filter(cluster_id=data["cluster_id"], namespace_id=data["namespace_id"], name=data["name"]).delete() user_log.log_add(activity_status="failed") raise error_codes.CheckFailed(_("创建失败,已通知管理员处理!"))
def get(self, request, project_id): """ 获取项目下所有的服务 """ cluster_dicts = self.get_project_cluster_info(request, project_id) cluster_data = cluster_dicts.get('results', {}) or {} project_kind = request.project.kind params = dict(request.GET.items()) params['env'] = 'mesos' if project_kind == MESOS_VALUE else 'k8s' # 获取命名空间的id namespace_dict = app_utils.get_ns_id_map( request.user.token.access_token, project_id) # 项目下的所有模板集id all_template_id_list = Template.objects.filter( project_id=project_id, edit_mode=TemplateEditMode.PageForm.value).values_list('id', flat=True) all_template_id_list = [ str(template_id) for template_id in all_template_id_list ] skip_namespace_list = list(K8S_SYS_NAMESPACE) skip_namespace_list.extend(K8S_PLAT_NAMESPACE) extended_routes = {} if project_kind == ProjectKind.K8S.value: extended_routes = get_svc_extended_routes(project_id) data = [] for cluster_info in cluster_data: cluster_id = cluster_info.get('cluster_id') if params.get('cluster_id') and params['cluster_id'] != cluster_id: continue cluster_name = cluster_info.get('name') code, cluster_services = self.get_services_by_cluster_id( request, params, project_id, cluster_id, project_kind=project_kind) if code != ErrorCode.NoError: continue for _s in cluster_services: # NOTE: 兼容处理,因为key: clusterId已被前端使用;通过非bcs创建的service,不一定包含cluster_id _s["clusterId"] = cluster_id _s["cluster_id"] = cluster_id _config = _s.get('data', {}) annotations = _config.get('metadata', {}).get('annotations', {}) _s['update_time'] = annotations.get(ANNOTATIONS_UPDATE_TIME, '') _s['updator'] = annotations.get(ANNOTATIONS_UPDATOR, '') _s['cluster_name'] = cluster_name _s['status'] = 'Running' _s['environment'] = cluster_info.get('environment') _s['can_update'] = True _s['can_update_msg'] = '' _s['can_delete'] = True _s['can_delete_msg'] = '' namespace_id = namespace_dict.get( (cluster_id, _s['namespace'])) if namespace_dict else None _s['namespace_id'] = namespace_id labels = _config.get('metadata', {}).get('labels', {}) template_id = labels.get(LABLE_TEMPLATE_ID) # 资源来源 source_type = labels.get(SOURCE_TYPE_LABEL_KEY) if not source_type: source_type = "template" if template_id else "other" _s['source_type'] = SOURCE_TYPE_MAP.get(source_type) if project_kind == ProjectKind.K8S.value: _s['access_info'] = get_svc_access_info( _config, _s['clusterId'], extended_routes) # 处理 k8s 的系统命名空间的数据 if project_kind == ProjectKind.K8S.value and _s[ 'namespace'] in skip_namespace_list: _s['can_update'] = _s['can_delete'] = False _s['can_update_msg'] = _s['can_delete_msg'] = _( "不允许操作系统命名空间") continue # 非模板集创建,可以删除但是不可以更新 _s['can_update'] = False _s['can_update_msg'] = _("所属模板集不存在,无法操作") if template_id and template_id in all_template_id_list: _s['can_update'] = True _s['can_update_msg'] = '' data += cluster_services # 按时间倒序排列 data.sort(key=lambda x: x.get('createTime', ''), reverse=True) if data: # 检查是否用命名空间的使用权限 perm = bcs_perm.Namespace(request, project_id, bcs_perm.NO_RES) data = perm.hook_perms(data, ns_id_flag='namespace_id', cluster_id_flag='clusterId', ns_name_flag='namespace') return APIResponse({ "code": ErrorCode.NoError, "data": { "data": data, "length": len(data) }, "message": "ok" })
def get_service_info(self, request, project_id, cluster_id, namespace, name): # noqa """获取单个 service 的信息""" project_kind = request.project.kind access_token = request.user.token.access_token params = { "env": "mesos" if project_kind == MESOS_VALUE else "k8s", "namespace": namespace, "name": name, } if project_kind == MESOS_VALUE: client = mesos.MesosClient(access_token, project_id, cluster_id, env=None) resp = client.get_services(params) # 跳转到模板集页面需要的参数 template_cate = 'mesos' relate_app_cate = 'application' else: client = k8s.K8SClient(access_token, project_id, cluster_id, env=None) resp = client.get_service(params) template_cate = 'k8s' relate_app_cate = 'deployment' if resp.get("code") != ErrorCode.NoError: raise ComponentError(resp.get("message")) resp_data = resp.get("data", []) if not resp_data: return APIResponse({ "code": 400, "message": _("查询不到 Service[{}] 的信息").format(name) }) s_data = resp_data[0].get('data', {}) labels = s_data.get('metadata', {}).get('labels') or {} # 获取命名空间的id namespace_id = app_utils.get_namespace_id(access_token, project_id, (cluster_id, namespace), cluster_id=cluster_id) instance_id = labels.get(LABLE_INSTANCE_ID) # 是否关联LB lb_balance = labels.get('BCSBALANCE') if lb_balance: s_data['isLinkLoadBalance'] = True s_data['metadata']['lb_labels'] = {'BCSBALANCE': lb_balance} else: s_data['isLinkLoadBalance'] = False lb_name = labels.get('BCSGROUP') # 获取模板集信息 template_id = labels.get(LABLE_TEMPLATE_ID) try: lasetest_ver = ShowVersion.objects.filter( template_id=template_id).order_by('-updated').first() show_version_name = lasetest_ver.name version_id = lasetest_ver.real_version_id version_entity = VersionedEntity.objects.get(id=version_id) except Exception: return APIResponse({ "code": 400, "message": _("模板集[id:{}]没有可用的版本,无法更新service").format(template_id) }) entity = version_entity.get_entity() # 获取更新人和创建人 annotations = s_data.get('metadata', {}).get('annotations', {}) creator = annotations.get(ANNOTATIONS_CREATOR, '') updator = annotations.get(ANNOTATIONS_UPDATOR, '') create_time = annotations.get(ANNOTATIONS_CREATE_TIME, '') update_time = annotations.get(ANNOTATIONS_UPDATE_TIME, '') # k8s 更新需要获取版本号 resource_version = s_data.get('metadata', {}).get('resourceVersion') or '' web_cache = annotations.get(ANNOTATIONS_WEB_CACHE) if not web_cache: # 备注中无,则从模板中获取,兼容mesos之前实例化过的模板数据 _services = entity.get('service') if entity else None _services_id_list = _services.split(',') if _services else [] _s = Service.objects.filter(id__in=_services_id_list, name=name).first() try: web_cache = _s.get_config.get('webCache') except Exception: pass else: try: web_cache = json.loads(web_cache) except Exception: pass s_data['webCache'] = web_cache deploy_tag_list = web_cache.get('deploy_tag_list') or [] app_weight = {} if project_kind == MESOS_VALUE: # 处理 mesos 中Service的关联数据 apps = entity.get('application') if entity else None application_id_list = apps.split(',') if apps else [] apps = Application.objects.filter(id__in=application_id_list) if apps: # 关联应用的权重 for key in labels: if key.startswith('BCS-WEIGHT-'): app_name = key[11:] _app = apps.filter(name=app_name).first() if _app: weight = int(labels[key]) app_weight[_app.app_id] = weight else: # 处理 k8s 中Service的关联数据 if not deploy_tag_list: _servs = entity.get('K8sService') if entity else None _serv_id_list = _servs.split(',') if _servs else [] _k8s_s = K8sService.objects.filter(id__in=_serv_id_list, name=name).first() if _k8s_s: deploy_tag_list = _k8s_s.get_deploy_tag_list() # 标签 和 备注 去除后台自动添加的 or_annotations = s_data.get('metadata', {}).get('annotations', {}) or_labels = s_data.get('metadata', {}).get('labels', {}) if or_labels: pub_keys = PUBLIC_LABELS.keys() show_labels = { key: or_labels[key] for key in or_labels if key not in pub_keys } s_data['metadata']['labels'] = show_labels if or_annotations: pub_an_keys = PUBLIC_ANNOTATIONS.keys() show_annotations = { key: or_annotations[key] for key in or_annotations if key not in pub_an_keys } remove_key(show_annotations, ANNOTATIONS_WEB_CACHE) s_data['metadata']['annotations'] = show_annotations return APIResponse({ "data": { 'service': [{ 'name': name, 'app_id': app_weight.keys(), 'app_weight': app_weight, 'deploy_tag_list': deploy_tag_list, 'config': s_data, 'version': version_id, 'lb_name': lb_name, 'instance_id': instance_id, 'namespace_id': namespace_id, 'cluster_id': cluster_id, 'namespace': namespace, 'creator': creator, 'updator': updator, 'create_time': create_time, 'update_time': update_time, 'show_version_name': show_version_name, 'resource_version': resource_version, 'template_id': template_id, 'template_cate': template_cate, 'relate_app_cate': relate_app_cate, }] } })
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": _("删除成功") }) curr_msg = resp.get("message") if "not found" in curr_msg or "node does not exist" in curr_msg: return APIResponse({ "code": ErrorCode.NoError, "message": _("删除成功") }) if resp.get("code") != ErrorCode.NoError: return APIResponse({ "code": resp.get("code") or DEFAULT_ERROR_CODE, "message": curr_msg }) return APIResponse({"code": resp.get("code"), "message": curr_msg})
def get(self, request, project_id): """ 获取项目下所有的服务 """ # 获取kind logger.debug("get project kind: %s" % project_id) project_kind = request.project.kind logger.debug("get project clusters: %s" % project_id) cluster_dicts = self.get_project_cluster_info(request, project_id) cluster_data = cluster_dicts.get('results', {}) or {} params = dict(request.GET.items()) params.update({ "env": "mesos" if project_kind == MESOS_VALUE else "k8s", }) data = [] access_token = request.user.token.access_token cluster = paas_cc.get_all_clusters(access_token, project_id, limit=constants.ALL_LIMIT) cluster = cluster.get('data', {}).get('results') or [] cluster = {i['cluster_id']: i['name'] for i in cluster} # 获取命名空间的id namespace_dict = app_utils.get_ns_id_map( request.user.token.access_token, project_id) # 项目下的所有模板集id all_template_id_list = Template.objects.filter( project_id=project_id).values_list('id', flat=True) all_template_id_list = [ str(template_id) for template_id in all_template_id_list ] skip_namespace_list = constants.K8S_SYS_NAMESPACE skip_namespace_list.extend(constants.K8S_PLAT_NAMESPACE) for cluster_info in cluster_data: cluster_id = cluster_info.get('cluster_id') if params.get('cluster_id') and params['cluster_id'] != cluster_id: continue cluster_name = cluster_info.get('name') code, cluster_services = self.get_services_by_cluster_id( request, params, project_id, cluster_id, project_kind=project_kind) if code != ErrorCode.NoError: continue for _s in cluster_services: _config = _s.get('data', {}) annotations = _config.get('metadata', {}).get('annotations', {}) _s['update_time'] = annotations.get(ANNOTATIONS_UPDATE_TIME, '') _s['updator'] = annotations.get(ANNOTATIONS_UPDATOR, '') _s['cluster_name'] = cluster_name _s['status'] = 'Running' _s['environment'] = cluster_info.get('environment') _s['can_update'] = True _s['can_update_msg'] = '' _s['can_delete'] = True _s['can_delete_msg'] = '' namespace_id = namespace_dict.get( (cluster_id, _s['namespace'])) if namespace_dict else None _s['namespace_id'] = namespace_id labels = _config.get('metadata', {}).get('labels', {}) template_id = labels.get(LABLE_TEMPLATE_ID) # 资源来源 source_type = labels.get(SOURCE_TYPE_LABEL_KEY) if not source_type: source_type = "template" if template_id else "other" _s['source_type'] = SOURCE_TYPE_MAP.get(source_type) # 处理 k8s 的系统命名空间的数据 if project_kind == 1 and _s['namespace'] in skip_namespace_list: _s['can_update'] = _s['can_delete'] = False _s['can_update_msg'] = _s['can_delete_msg'] = _( "不允许操作系统命名空间") continue # 非模板集创建,可以删除但是不可以更新 _s['can_update'] = False _s['can_update_msg'] = _("所属模板集不存在,无法操作") if template_id and template_id in all_template_id_list: _s['can_update'] = True _s['can_update_msg'] = '' data += cluster_services # 按时间倒序排列 data.sort(key=lambda x: x.get('createTime', ''), reverse=True) if data: # 检查是否用命名空间的使用权限 perm = bcs_perm.Namespace(request, project_id, bcs_perm.NO_RES) data = perm.hook_perms(data, ns_id_flag='namespace_id', cluster_id_flag='clusterId', ns_name_flag='namespace') return APIResponse({ "code": ErrorCode.NoError, "data": { "data": data, "length": len(data) }, "message": "ok" })
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})