def list(self, request, project_id, cluster_id=None): access_token = request.user.token.access_token cluster_map = self._get_cluster_map(project_id) namespace_map = self._get_cluster_map(project_id) data = [] if cluster_id: if cluster_id not in cluster_map: raise error_codes.APIError(_("cluster_id not valid")) client = k8s.K8SClient(access_token, project_id, cluster_id, env=None) items = self._handle_items(cluster_id, cluster_map, namespace_map, client.list_service_monitor()) data.extend(items) else: for cluster in cluster_map.values(): cluster_id = cluster["cluster_id"] cluster_env = cluster.get("environment") client = k8s.K8SClient(access_token, project_id, cluster_id, env=cluster_env) items = self._handle_items(cluster_id, cluster_map, namespace_map, client.list_service_monitor()) data.extend(items) perm = bcs_perm.Namespace(request, project_id, bcs_perm.NO_RES) data = perm.hook_perms(data, ns_id_flag="namespace_id") self.filter_no_perm(data) return Response(data)
def list(self, request, project_id, cluster_id=None): access_token = request.user.token.access_token data = [] if cluster_id: client = k8s.K8SClient(access_token, project_id, cluster_id, env=None) items = self._handle_items(cluster_id, client.list_service_monitor()) data.extend(items) else: cluster_list = self._get_cluster_list(project_id) for cluster in cluster_list: cluster_id = cluster["cluster_id"] cluster_env = cluster.get("environment") client = k8s.K8SClient(access_token, project_id, cluster_id, env=cluster_env) items = self._handle_items(cluster_id, client.list_service_monitor()) data.extend(items) return Response(data)
def update(self, request, project_id, cluster_id): access_token = request.user.token.access_token client = k8s.K8SClient(access_token, project_id, cluster_id, env=None) resp = client.get_prometheus("thanos", "po-prometheus-operator-prometheus") spec = resp.get("spec") if not spec: raise error_codes.APIError(_("Prometheus未安装, 请联系管理员解决")) need_update = False # 获取原来的值不变,覆盖更新 for container in spec["containers"]: if container["name"] not in settings.PROMETHEUS_VERSIONS: continue image = settings.PROMETHEUS_VERSIONS[container["name"]] if semantic_version.Version( self._get_version(image)) <= semantic_version.Version( self._get_version(container["image"])): continue need_update = True container["image"] = image if not need_update: raise error_codes.APIError(_("已经最新版本, 不需要升级")) patch_spec = {"spec": {"containers": spec["containers"]}} resp = client.update_prometheus("thanos", "po-prometheus-operator-prometheus", patch_spec) message = _("更新Metrics: 升级 thanos-sidecar 成功") self._activity_log(project_id, request.user.username, "update thanos-sidecar", message, True) return Response(resp)
def delete_instance_task(access_token, inst_id_list, project_kind): """后台更新删除实例是否被删除成功""" # 通过instance id获取到相应的记录,然后查询mesos/k8s的实例状态 inst_info = InstanceConfig.objects.filter(id__in=inst_id_list) is_polling = True all_count = len(inst_info) end_time = datetime.now() + POLLING_TIMEOUT while is_polling: deleted_id_list = [] time.sleep(POLLING_INTERVAL_SECONDS) for info in inst_info: inst_conf = json.loads(info.config) metadata = inst_conf.get("metadata") or {} labels = metadata.get("labels") or {} cluster_id = labels.get("io.tencent.bcs.clusterid") namespace = labels.get("io.tencent.bcs.namespace") project_id = labels.get("io.tencent.paas.projectid") category = info.category name = metadata.get("name") # 根据类型获取查询 client = k8s.K8SClient(access_token, project_id, cluster_id, None) curr_func = getattr(client, FUNC_MAP[category] % "get") resp = curr_func({"name": name, "namespace": namespace}) if not resp.get("data"): deleted_id_list.append(info.id) # 删除名称+命名空间+类型 InstanceConfig.objects.filter(name=info.name, namespace=info.namespace, category=info.category).update( is_deleted=True, deleted_time=datetime.now()) if len(deleted_id_list) == all_count or datetime.now() > end_time: is_polling = False
def get_secrets_by_cluster_id(self, request, params, project_id, cluster_id, project_kind=MESOS_VALUE): """查询secrets """ access_token = request.user.token.access_token search_fields = copy.deepcopy(DEFAULT_SEARCH_FIELDS) if project_kind == MESOS_VALUE: search_fields.append("data.datas") params.update({"field": ",".join(search_fields)}) client = mesos.MesosClient(access_token, project_id, cluster_id, env=None) resp = client.get_secrets(params) else: search_fields.append("data.data") params.update({"field": ",".join(search_fields)}) client = k8s.K8SClient(access_token, project_id, cluster_id, env=None) resp = client.get_secret(params) if resp.get("code") != ErrorCode.NoError: logger.error(u"bcs_api error: %s" % resp.get("message", "")) return resp.get("code", DEFAULT_ERROR_CODE), resp.get( "message", _("请求出现异常!")) data = resp.get("data") or [] # data = data_handler(resp.get("data") or [], project_kind) return 0, data
def delete_hpa(request, project_id, cluster_id, namespace, namespace_id, name): username = request.user.username access_token = request.user.token.access_token client = k8s.K8SClient(access_token, project_id, cluster_id, env=None) try: client.delete_hpa(namespace, name) except client.rest.ApiException as error: if error.status == 404: # 404 错误忽略 pass else: logger.info('delete hpa error, %s', error) return False, "删除HPA资源失败" except Exception as error: logger.error('delete hpa error, %s', error) return False, "删除HPA资源失败" # 删除成功则更新状态 instances = InstanceConfig.objects.filter( namespace=namespace_id, category=K8sResourceName.K8sHPA.value, name=name) if not instances: instances.update(updator=username, oper_type=DELETE_INSTANCE, deleted_time=timezone.now(), is_deleted=True, is_bcs_success=True) return True, ''
def get(self, request, project_id, cluster_id): """获取targets列表 """ access_token = request.user.token.access_token client = k8s.K8SClient(access_token, project_id, cluster_id, env=None) resp = client.get_prometheus("thanos", "po-prometheus-operator-prometheus") spec = resp.get("spec") or {} if not spec: raise error_codes.APIError(_("Prometheus未安装,请联系管理员解决")) data = {"need_update": False, "update_tooltip": ""} for container in spec.get("containers") or []: if container["name"] not in settings.PROMETHEUS_VERSIONS: continue image = settings.PROMETHEUS_VERSIONS[container["name"]] if semantic_version.Version( self._get_version(image)) <= semantic_version.Version( self._get_version(container["image"])): continue update_tooltip = _( "当前【{}】版本较低, 查询 Endpoints 功能将不可用, 请升级到最新版本").format( container["name"]) need_update = True data["need_update"] = need_update data["update_tooltip"] = update_tooltip break return Response(data)
def delete_single_resource(self, request, project_id, cluster_id, namespace, namespace_id, name): username = request.user.username access_token = request.user.token.access_token if namespace in K8S_SYS_NAMESPACE: return { "code": 400, "message": _("不允许操作系统命名空间[{}]").format(','.join(K8S_SYS_NAMESPACE)), } client = k8s.K8SClient(access_token, project_id, cluster_id, env=None) curr_func = getattr(client, "delete_%s" % self.category) resp = curr_func(namespace, name) if resp.get("code") == ErrorCode.NoError: # 删除成功则更新状态 now_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') InstanceConfig.objects.filter(namespace=namespace_id, category=self.cate, name=name).update( creator=username, updator=username, oper_type=DELETE_INSTANCE, updated=now_time, deleted_time=now_time, is_deleted=True, is_bcs_success=True, ) return { "code": resp.get("code"), "message": resp.get("message"), }
def get_cluster_hpa_list(request, project_id, cluster_id, cluster_env, cluster_name, namespace=None): """获取基础hpa列表""" access_token = request.user.token.access_token project_code = request.project.english_name hpa_list = [] try: if request.project.kind == ProjectKind.MESOS.value: client = mesos.MesosClient(access_token, project_id, cluster_id, env=cluster_env) hpa = client.list_hpa(namespace).get("data") or [] hpa_list = slz_mesos_hpa_info(hpa, project_code, cluster_name, cluster_env, cluster_id) else: client = k8s.K8SClient(access_token, project_id, cluster_id, env=cluster_env) hpa = client.list_hpa(namespace).get("items") or [] hpa_list = slz_k8s_hpa_info(hpa, project_code, cluster_name, cluster_env, cluster_id) except Exception as error: logger.error("get hpa list error, %s", error) return hpa_list
def reschedule_pod_taskgroup(access_token, project_id, data, kind, log): """重新调度pod or taskgroup """ if kind == 2: for cluster_id, taskgroup_info in data.items(): client = mesos.MesosClient( access_token, project_id, cluster_id, None ) for info in taskgroup_info: resp = client.rescheduler_mesos_taskgroup( info["namespace"], info["app_name"], info["taskgroup_name"] ) # 如果删除失败,直接报错 if resp.get("code") != ErrorCode.NoError: update_log_info(log, models.CommonStatus.ScheduleFailed, resp.get("message")) return False else: for cluster_id, pod_info in data.items(): client = k8s.K8SClient( access_token, project_id, cluster_id, None ) for info in pod_info: resp = client.delete_pod(info["namespace"], info["pod_name"]) if resp.get("code") != ErrorCode.NoError: update_log_info(log, models.CommonStatus.ScheduleFailed, resp.get("message")) return False update_log_info(log, models.CommonStatus.Normal, _("调度结束!")) return True
def get(self, request, project_id, cluster_id, namespace, name): """ 获取项目下所有的endpoints """ # 获取kind flag, project_kind = self.get_project_kind(request, project_id) if not flag: return project_kind access_token = request.user.token.access_token params = {"name": name, "namespace": namespace} if project_kind == MESOS_VALUE: client = mesos.MesosClient(access_token, project_id, cluster_id, env=None) resp = client.get_endpoints(params) else: client = k8s.K8SClient(access_token, project_id, cluster_id, env=None) resp = client.get_endpoints(params) if resp.get("code") != ErrorCode.NoError: return APIResponse({ "code": resp.get("code", DEFAULT_ERROR_CODE), "message": resp.get("message", _("请求出现异常!")) }) return APIResponse({ "code": ErrorCode.NoError, "data": resp.get("data"), "message": "ok" })
def get_pod_info(access_token, project_id, cluster_id, data, log): """获取pod下数量 """ k8s_client = k8s.K8SClient( access_token, project_id, cluster_id, None ) rsp_bcs = k8s_client.get_pod( host_ips=[data["inner_ip"]], field="namespace,resourceName,clusterId" ) if rsp_bcs.get("code") != ErrorCode.NoError: update_log_info(log, models.CommonStatus.ScheduleFailed, rsp_bcs.get("message")) return None cluster_ns_pod_data = {} for i in rsp_bcs["data"]: cluster_id = i.get("clusterId") namespace = i.get("namespace") if namespace not in K8S_SKIP_NS_LIST: pod_name = i.get("resourceName") item = { "namespace": namespace, "pod_name": pod_name } if cluster_id in cluster_ns_pod_data: cluster_ns_pod_data[cluster_id].append(item) else: cluster_ns_pod_data[cluster_id] = [item] return cluster_ns_pod_data
def get_services_by_cluster_id(self, request, params, project_id, cluster_id, project_kind=MESOS_VALUE): """查询services""" access_token = request.user.token.access_token if project_kind == MESOS_VALUE: client = mesos.MesosClient(access_token, project_id, cluster_id, env=None) resp = client.get_services(params) else: client = k8s.K8SClient(access_token, project_id, cluster_id, env=None) resp = client.get_service(params) if resp.get("code") != ErrorCode.NoError: logger.error(u"bcs_api error: %s" % resp.get("message", "")) return resp.get("code", DEFAULT_ERROR_CODE), resp.get( "message", _("请求出现异常!")) return ErrorCode.NoError, resp.get("data", [])
def get_node_metric(request, access_token, project_id, cluster_id, cluster_type): node = paas_cc.get_node_list(access_token, project_id, cluster_id, params={"limit": 10000}) if node.get('code') != 0: raise APIError(node.get('message')) # 过滤掉状态为removed的机器 node_data = [ info for info in node.get("data", {}).get("results") or [] if info.get("status") not in [constants.NodeStatus.REMOVED.value] ] # 重新组装数据 node = { "count": len(node_data), "results": node_data, } node_total = node['count'] node_actived = 0 node_disabled = 0 if cluster_type != ClusterCOES.MESOS.value: # namespace 获取处理 client = k8s.K8SClient(access_token, project_id, cluster_id=cluster_id, env=None) namespace = client.get_namespace() if not namespace.get('result'): raise APIError(namespace.get('message')) # 节点状态处理 计算k8s有容器的节点 if node_total > 0: node_ips = [i['inner_ip'] for i in node['results']] containers = k8s_containers(request, project_id, cluster_id, node_ips) for node in node_ips: if containers.get(node, 0) > 0: node_actived += 1 else: # 节点状态处理 计算mesos有容器的节点 if node_total > 0: node_ips = [i['inner_ip'] for i in node['results']] containers = mesos_containers(request, project_id, cluster_id, node_ips) for node in node_ips: if containers.get(node, 0) > 0: node_actived += 1 node_disabled = node_total - node_actived data = { 'total': node_total, 'actived': node_actived, 'disabled': node_disabled } return data
def delete(self, request, project_id, cluster_id, namespace, name): """删除servicemonitor """ access_token = request.user.token.access_token client = k8s.K8SClient(access_token, project_id, cluster_id, env=None) result = client.delete_service_monitor(namespace, name) if result.get("status") == "Failure": raise error_codes.APIError(result.get("message", "")) return Response(result)
def create(self, request, project_id, cluster_id=None): slz = self.serializer_class(data=request.data) slz.is_valid(raise_exception=True) data = slz.validated_data if cluster_id is None: cluster_id = data["cluster_id"] self._validate_namespace_use_perm(request, project_id, [data["namespace"]]) endpoints = [{ "path": data["path"], "interval": data["interval"], "port": data["port"], "params": data.get("params", {}), }] spec = { "apiVersion": "monitoring.coreos.com/v1", "kind": "ServiceMonitor", "metadata": { "labels": { "release": "po", "io.tencent.paas.source_type": "bcs", "io.tencent.bcs.service_name": data["service_name"], }, "name": data["name"], "namespace": data["namespace"], }, "spec": { "endpoints": endpoints, "selector": { "matchLabels": data["selector"] }, "sampleLimit": data["sample_limit"], }, } client = k8s.K8SClient(request.user.token.access_token, project_id, cluster_id, env=None) result = client.create_service_monitor(data["namespace"], spec) if result.get("status") == "Failure": message = _("创建Metrics:{}失败, [命名空间:{}], {}").format( data["name"], data["namespace"], result.get("message", "")) self._activity_log(project_id, request.user.username, data["name"], message, False) raise error_codes.APIError(result.get("message", "")) message = _("创建Metrics:{}成功, [命名空间:{}]").format( data["name"], data["namespace"]) self._activity_log(project_id, request.user.username, data["name"], message, True) return Response(result)
def get_cluster_hpa_list(access_token, project_id, cluster_id, cluster_env, cluster_name): """获取基础hpa列表 """ hpa_list = [] client = k8s.K8SClient(access_token, project_id, cluster_id, env=cluster_env) hpa = client.list_hpa().to_dict()['items'] for _config in hpa: labels = _config.get('metadata', {}).get('labels') or {} # 获取模板集信息 template_id = labels.get(instance_constants.LABLE_TEMPLATE_ID) # 资源来源 source_type = labels.get(instance_constants.SOURCE_TYPE_LABEL_KEY) if not source_type: source_type = "template" if template_id else "other" annotations = _config.get('metadata', {}).get('annotations') or {} data = { 'cluster_name': cluster_name, 'cluster_id': cluster_id, 'name': _config['metadata']['name'], 'namespace': _config['metadata']['namespace'], 'max_replicas': _config['spec']['max_replicas'], 'min_replicas': _config['spec']['min_replicas'], 'current_replicas': _config['status']['current_replicas'], 'current_metrics_display': get_current_metrics_display(_config), 'current_metrics': get_current_metrics(_config), 'source_type': application_constants.SOURCE_TYPE_MAP.get(source_type), 'creator': annotations.get(instance_constants.ANNOTATIONS_CREATOR, ''), 'create_time': annotations.get(instance_constants.ANNOTATIONS_CREATE_TIME, ''), } data['update_time'] = annotations.get( instance_constants.ANNOTATIONS_UPDATE_TIME, data['create_time']) data['updator'] = annotations.get( instance_constants.ANNOTATIONS_UPDATOR, data['creator']) hpa_list.append(data) return hpa_list
def get_host_pod(access_token, project_id, cluster_id, inner_ip_list): """查询k8s机器下的pod """ k8s_client = k8s.K8SClient( access_token, project_id, cluster_id, None ) resp = k8s_client.get_pod( host_ips=inner_ip_list, field="namespace" ) return resp.get("data")
def get_ingress_by_cluser_id(self, request, params, project_id, cluster_id): """查询configmaps""" access_token = request.user.token.access_token client = k8s.K8SClient(access_token, project_id, cluster_id, env=None) resp = client.get_ingress(params) if resp.get("code") != ErrorCode.NoError: logger.error(u"bcs_api error: %s" % resp.get("message", "")) return resp.get("code", ErrorCode.UnknownError), resp.get("message", _("请求出现异常!")) data = resp.get("data") or [] return 0, data
def _get_client(self, request, project_id, cluster_id): if request.project.kind == ProjectKind.MESOS.value: client = mesos.MesosClient(request.user.token.access_token, project_id, cluster_id, env=None) else: client = k8s.K8SClient(request.user.token.access_token, project_id, cluster_id, env=None) return client
def create_instance(access_token, cluster_id, ns, data, project_id=None, category="application", kind=2): """创建实例""" client = k8s.K8SClient(access_token, project_id, cluster_id, None) curr_func = getattr(client, FUNC_MAP[category] % "create") resp = curr_func(ns, data) resp = DEFAULT_RESPONSE return resp
def delete_single_service(self, request, project_id, project_kind, cluster_id, namespace, namespace_id, name): username = request.user.username access_token = request.user.token.access_token if project_kind == MESOS_VALUE: client = mesos.MesosClient(access_token, project_id, cluster_id, env=None) resp = client.delete_service(namespace, name) s_cate = 'service' else: if namespace in K8S_SYS_NAMESPACE: return { "code": 400, "message": _("不允许操作系统命名空间[{}]").format(','.join(K8S_SYS_NAMESPACE)), } client = k8s.K8SClient(access_token, project_id, cluster_id, env=None) resp = client.delete_service(namespace, name) s_cate = 'K8sService' delete_svc_extended_routes(request, project_id, cluster_id, namespace, name) if resp.get("code") == ErrorCode.NoError: # 删除成功则更新状态 now_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') InstanceConfig.objects.filter( namespace=namespace_id, category=s_cate, name=name, ).update( creator=username, updator=username, oper_type=DELETE_INSTANCE, updated=now_time, deleted_time=now_time, is_deleted=True, is_bcs_success=True, ) return { "code": resp.get("code"), "message": resp.get("message"), }
def list(self, request, project_id, cluster_id): """获取targets列表""" access_token = request.user.token.access_token if request.project.kind == ProjectKind.MESOS.value: client = mesos.MesosClient(access_token, project_id, cluster_id, env=None) resp = client.get_services({"env": "mesos"}) else: client = k8s.K8SClient(access_token, project_id, cluster_id, env=None) resp = client.get_service({"env": "k8s"}) data = self._filter_service(resp.get("data") or []) return Response(data)
def k8s_container_num(self): client = bcs_k8s.K8SClient(self.access_token, self.project_id, self.cluster_id, None) host_pod_info = client.get_pod( host_ips=[self.node_ip], field=','.join(['data.status.containerStatuses', 'data.metadata.namespace']) ) if host_pod_info.get('code') != ErrorCode.NoError: raise error_codes.APIError(host_pod_info.get('message')) count = 0 for i in host_pod_info.get('data', []): namespace = i.get('data', {}).get('metadata', {}).get('namespace') if namespace in constants.K8S_SKIP_NS_LIST: continue count += len(i.get('data', {}).get('status', {}).get('containerStatuses', [])) return count
def get_k8s_category_status( access_token, cluster_id, instance_name, project_id=None, category="application", field=None, namespace=None): """查询mesos下application和deployment的状态 """ client = k8s.K8SClient( access_token, project_id, cluster_id, None ) curr_func = getattr(client, FUNC_MAP[category] % "get") resp = curr_func({ "name": instance_name, "field": field or "data.status", "namespace": namespace, }) return resp
def update(self, request, project_id, cluster_id, namespace, name): access_token = request.user.token.access_token slz = serializers.ServiceMonitorUpdateSLZ(data=request.data) slz.is_valid(raise_exception=True) data = slz.validated_data client = k8s.K8SClient(access_token, project_id, cluster_id, env=None) result = client.get_service_monitor(namespace, name) if result.get("status") == "Failure": raise error_codes.APIError(result.get("message", "")) spec = self.merge_spec(result, data) result = client.update_service_monitor(namespace, name, spec) return Response(result)
def k8s_containers(request, project_id, cluster_id, host_ips): """k8s pod容器信息""" client = k8s.K8SClient(request.user.token.access_token, project_id, cluster_id, None) rsp = client.get_pod( host_ips, field="data.status.containerStatuses.containerID,data.status.hostIP") if rsp.get("code") != ErrorCode.NoError: return {} containers = {} for info in rsp["data"]: containers.setdefault(info["data"]["status"]["hostIP"], 0) containers[info["data"]["status"]["hostIP"]] += len( info["data"]["status"]["containerStatuses"]) return containers
def get(self, request, project_id, cluster_id, namespace, name): """获取单个serviceMonitor """ access_token = request.user.token.access_token client = k8s.K8SClient(access_token, project_id, cluster_id, env=None) result = client.get_service_monitor(namespace, name) if result.get("status") == "Failure": raise error_codes.APIError(result.get("message", "")) if result.get("metadata"): result["metadata"] = { k: v for k, v in result["metadata"].items() if k not in self.filtered_metadata } return Response(result)
def get_services_by_cluster_id(self, request, params, project_id, cluster_id): """查询services""" if get_cluster_type(cluster_id) == ClusterType.SHARED: return ErrorCode.NoError, [] access_token = request.user.token.access_token client = k8s.K8SClient(access_token, project_id, cluster_id, env=None) resp = client.get_service(params) if resp.get("code") != ErrorCode.NoError: logger.error(u"bcs_api error: %s" % resp.get("message", "")) return resp.get("code", DEFAULT_ERROR_CODE), resp.get( "message", _("请求出现异常!")) return ErrorCode.NoError, resp.get("data", [])
def get_secrets_by_cluster_id(self, request, params, project_id, cluster_id): """查询secrets""" if get_cluster_type(cluster_id) == ClusterType.SHARED: return 0, [] search_fields = copy.deepcopy(DEFAULT_SEARCH_FIELDS) search_fields.append("data.data") params.update({"field": ",".join(search_fields)}) client = k8s.K8SClient(request.user.token.access_token, project_id, cluster_id, env=None) resp = client.get_secret(params) if resp.get("code") != ErrorCode.NoError: logger.error(u"bcs_api error: %s" % resp.get("message", "")) return resp.get("code", ErrorCode.UnknownError), resp.get("message", _("请求出现异常!")) data = resp.get("data") or [] return 0, data