def _generate(self, inject_configs: List[Dict], bcs_variables: Dict[str, str]) -> List[ResourceData]: """注入变量、渲染系统配置到原始的manifest中,最终生成待下发的ResourceData列表""" resource_list = [] for raw_manifest in self._get_raw_manifests(): rendered_manifest = self._render_with_variables( raw_manifest, bcs_variables) for manifest in self._inject_bcs_info(rendered_manifest, inject_configs): self._set_namespace(manifest) resource_list.append( ResourceData( kind=manifest.get('kind'), name=getitems(manifest, 'metadata.name'), namespace=getitems(manifest, 'metadata.namespace', default=''), manifest=manifest, version=self.res_ctx.show_version.name, revision=self.res_ctx.show_version.latest_revision, )) return resource_list
def filter_pods(self, namespace, filter_reference_name, filter_pod_name, host_ips): resp = self.api_instance.list_namespaced_pod(namespace, _preload_content=False) data = json.loads(resp.data) pods_map = {} for info in data.get('items') or []: pod_name = getitems(info, ['metadata', 'name'], '') pod_namespace = getitems(info, ['metadata', 'namespace'], '') item = self.render_resource(self.resource_kind, info, pod_name, pod_namespace) # 如果过滤参数都不存在时,返回所有 if not (filter_reference_name or filter_pod_name or host_ips): pods_map[pod_name] = item # TODO: 是否有必要把下面几个拆分到方法中 # 过滤reference if filter_reference_name: pods_map = self.filter_pods_by_reference_name( pod_name, info, filter_reference_name, pods_map, item) # 过滤pod name if filter_pod_name and pod_name == filter_pod_name: pods_map[pod_name] = item # 过滤host ip if host_ips: pods_map = self.filter_pods_by_ips(pod_name, info, host_ips, pods_map, item) # 转换为list,防止view层出现错误`TypeError: 'dict_values' object does not support indexing` return list(pods_map.values())
def parse(self) -> str: """ 获取 Pod 总状态 """ # 1. 默认使用 Pod.Status.Phase self.tol_status = getitems(self.pod, 'status.phase') # 2. 若有具体的 Pod.Status.Reason 则使用 if getitems(self.pod, 'status.reason'): self.tol_status = getitems(self.pod, 'status.reason') # 3. 根据 Pod 容器状态更新状态 self._update_status_by_init_container_statuses() if not self.initializing: self._update_status_by_container_statuses() # 4. 根据 Pod.Metadata.DeletionTimestamp 更新状态 if getitems(self.pod, 'metadata.deletionTimestamp'): if getitems(self.pod, 'status.reason') == 'NodeLost': self.tol_status = SimplePodStatus.PodUnknown.value else: self.tol_status = SimplePodStatus.Terminating.value # 5. 若状态未初始化或在转移中丢失,则标记为未知状态 if not self.tol_status: self.tol_status = SimplePodStatus.PodUnknown.value return self.tol_status
def render_resource(self, resource_type, resource, resource_name, namespace): if not getitems(resource, ["metadata", "annotations"], {}): resource["metadata"]["annotations"] = {} if not getitems(resource, ["metadata", "labels"], {}): resource["metadata"]["labels"] = {} create_time = getitems(resource, ["metadata", "creationTimestamp"], "") if create_time: # create_time format: '2019-12-16T09:10:59Z' d_time = arrow.get(create_time).datetime create_time = timezone.localtime(d_time).strftime( "%Y-%m-%d %H:%M:%S") annotations = getitems(resource, ["metadata", "annotations"], {}) update_time = annotations.get( "io.tencent.paas.updateTime") or create_time if update_time: update_time = normalize_datetime(update_time) labels = getitems(resource, ["metadata", "labels"], {}) return { "data": resource, "clusterId": labels.get("io.tencent.bcs.clusterid") or "", "resourceName": resource_name, "resourceType": resource_type, "createTime": create_time, "updateTime": update_time, "namespace": namespace, }
def retrieve(self, request, project_id, cluster_id, namespace, name): namespace_id = self.get_namespace_id(request, project_id, cluster_id, namespace, name) # 校验查看权限 self.can_view(request, project_id, cluster_id, namespace_id) client = mesos.MesosClient(request.user.token.access_token, project_id, cluster_id, env=None) result = client.get_custom_resource(name, namespace) data = { 'name': name, 'namespace': namespace, 'namespace_id': namespace_id, 'cluster_id': cluster_id, 'clb_name': getitems(result, ['metadata', 'labels', CLB_NAME_LABEL], default=''), 'clb_region': getitems(result, ['metadata', 'labels', CLB_REGION_LABEL], default=''), 'spec': result['spec'], 'config': result, } return response.Response(data)
def get_svc_access_info(manifest, cluster_id, extended_routes): """ { 'external': { 'NodePort': ['node_ip:{node_port}'], }, 'internal': { 'ClusterIP': [':{port} {Protocol}'] } } """ access_info = {'external': {}, 'internal': {}} svc_type = getitems(manifest, ['spec', 'type']) ports = getitems(manifest, ['spec', 'ports']) if not ports: return access_info if svc_type == 'ClusterIP': cluster_ip = getitems(manifest, ['spec', 'clusterIP']) if not cluster_ip or cluster_ip == 'None': cluster_ip = '--' access_info['internal'] = { 'ClusterIP': [f"{cluster_ip}:{p['port']} {p['protocol']}" for p in ports] } elif svc_type == 'NodePort': access_info['external'] = { 'NodePort': [f":{p['nodePort']}" for p in ports] } return access_info
def compose_data(self, pod_info, container_id): """根据container id处理数据""" ret_data = {} if not (pod_info and container_id): return ret_data # pod_info type is list, and only one pod_info = pod_info[0] container_statuses = getitems(pod_info, ['data', 'status', 'containerStatuses'], default=[]) status = getitems(pod_info, ['data', 'status'], default={}) spec = getitems(pod_info, ['data', 'spec'], default={}) labels = getitems(pod_info, ['data', 'metadata', 'labels'], default={}) # 开始数据匹配 container_data = { info.get("name"): info for info in spec.get('containers') or [] } for info in container_statuses: curr_container_id = info.get('containerID') # container_id format: "docker://ad7034695ae7f911babf771447b65e1cb97f3f1987ad214c22decba0dd3fa121" if container_id not in curr_container_id: continue container_spec = container_data.get(info.get('name'), {}) ret_data = self.compose_container_data(container_id, container_spec, info, spec, status, labels) break return ret_data
def list(self, request, project_id): """通过项目或集群拉取ingress """ cluster_id = request.query_params.get('cluster_id') project_clusters = self.get_clusters(request, project_id) project_namespaces = self.get_project_namespaces(request, project_id) cluster_id_list = [cluster_id ] if cluster_id else project_clusters.keys() # 通过集群拉取ingress数据 ingress_list = [] for cluster_id in cluster_id_list: data = network_utils.get_cluster_ingresses( request.user.token.access_token, project_id, cluster_id) for info in data: create_time = getitems(info, ['metadata', 'creationTimestamp']) if create_time: d_time = arrow.get(create_time).datetime create_time = timezone.localtime(d_time).strftime( '%Y-%m-%d %H:%M:%S') update_time = getitems( info, ['metadata', 'annotations', 'io.tencent.paas.updateTime']) namespace_name = getitems(info, ['metadata', 'namespace'], default='') namespace_id = project_namespaces.get( (cluster_id, namespace_name), {}).get('id', DEFAULT_NAMESPACE_ID) ingress_list.append({ 'name': getitems(info, ['metadata', 'name'], default=''), 'namespace': namespace_name, 'namespace_id': namespace_id, 'cluster_id': cluster_id, 'spec': info['spec'], 'config': info, 'cluster_name': project_clusters[cluster_id]['name'], 'environment': project_clusters[cluster_id]['environment'], 'create_time': create_time, 'update_time': update_time if update_time else create_time }) if ingress_list: # 检查是否用命名空间的使用权限 perm = bcs_perm.Namespace(request, project_id, bcs_perm.NO_RES) ingress_list = perm.hook_perms(ingress_list, ns_id_flag='namespace_id', ns_name_flag='namespace') # 按照更新时间排序 ingress_list.sort(key=lambda info: info['update_time'], reverse=True) return response.Response(ingress_list)
def query_cluster_nodes(ctx_cluster: CtxCluster) -> Dict[str, Dict]: # 查询集群下node信息 client = Node(ctx_cluster) nodes = client.list() # 根据传入的inner_ip过滤节点信息 data = {} for node in nodes: node_data = node.data # 解析数据用于前端展示 metadata = node_data.get("metadata", {}) labels = metadata.get("labels", {}) # 过滤掉master if labels.get("node-role.kubernetes.io/master") == "true": continue taints = getitems(node_data, ["spec", "taints"], []) # 组装数据,用于展示 data[node.inner_ip] = { "inner_ip": node.inner_ip, "name": node.name, "labels": labels, "taints": taints, "status": get_node_status(getitems(node_data, ["status", "conditions"], [])), "unschedulable": getitems(node_data, ["spec", "unschedulable"], False), } return data
def test_reschedule(self, api_client): """ 测试重新调度 Pod TODO 可考虑 mock 掉下发集群操作,仅验证接口功能 """ # 创建有父级资源的 Pod,测试重新调度 deploy_manifest = load_demo_manifest('workloads/simple_deployment') deploy_name = deploy_manifest['metadata']['name'] api_client.post(f'{DAU_PREFIX}/workloads/deployments/', data={'manifest': deploy_manifest}) # 等待 Deployment 下属 Pod 创建 time.sleep(3) # 找到 Deployment 下属的 第一个 Pod Name resp = api_client.get( f'{DAU_PREFIX}/namespaces/{TEST_NAMESPACE}/workloads/pods/', data={ 'label_selector': 'app=nginx', 'owner_kind': 'Deployment', 'owner_name': deploy_name }, ) pods = getitems(resp.json(), 'data.manifest.items', []) pod_name = getitems(pods[0], 'metadata.name') resp = api_client.put( f'{DAU_PREFIX}/namespaces/{TEST_NAMESPACE}/workloads/pods/{pod_name}/reschedule/' ) assert resp.json()['code'] == 0 assert getitems(resp.json(), 'data.metadata.name') == pod_name # 清理测试用的资源 resp = api_client.delete( f'{DAU_PREFIX}/namespaces/{TEST_NAMESPACE}/workloads/deployments/{deploy_name}/' ) assert resp.json()['code'] == 0
def _generate(self, namespace_id, params) -> List[ResourceData]: resource_list = [] # instance_entity like {"Deployment": [1, 2]} instance_entity = self.res_ctx.instance_entity for kind in instance_entity: for entity_id in instance_entity[kind]: config_generator = GENERATOR_DICT.get(kind)(entity_id, namespace_id, is_validate=True, **params) config = config_generator.get_config_profile() try: manifest = json.loads(config) except Exception: manifest = config resource_list.append( ResourceData( kind=manifest.get('kind'), name=getitems(manifest, 'metadata.name'), namespace=getitems(manifest, 'metadata.namespace'), manifest=manifest, version=self.res_ctx.show_version.name, revision=self.res_ctx.show_version.latest_revision, ) ) return resource_list
def build(self) -> Dict: """ 构造展示用的容器详情信息 """ for cs in getitems(self.pod, 'status.containerStatuses', []): if self.container_name == cs['name']: container_status = cs break else: raise ResourceNotExist( _('容器 {} 状态信息不存在').format(self.container_name)) labels = getitems(self.pod, 'metadata.labels', {}) spec, status = self.pod['spec'], self.pod['status'] for csp in spec.get('containers', []): if self.container_name == csp['name']: container_spec = csp break else: raise ResourceNotExist( _('容器 {} 模板(Spec)信息不存在').format(self.container_name)) return { 'host_name': get_with_placeholder(spec, 'nodeName'), 'host_ip': get_with_placeholder(status, 'hostIP'), 'container_ip': get_with_placeholder(status, 'podIP'), 'container_id': self._extract_container_id( get_with_placeholder(container_status, 'containerID')), 'container_name': self.container_name, 'image': get_with_placeholder(container_status, 'image'), 'network_mode': get_with_placeholder(spec, 'dnsPolicy'), # 端口映射 'ports': container_spec.get('ports', []), # 命令 'command': { 'command': get_with_placeholder(container_spec, 'command', ''), 'args': ' '.join(container_spec.get('args', [])), }, # 挂载卷 'volumes': [{ 'host_path': get_with_placeholder(mount, 'name'), 'mount_path': get_with_placeholder(mount, 'mountPath'), 'readonly': get_with_placeholder(mount, 'readOnly'), } for mount in container_spec.get('volumeMounts', [])], # 标签 'labels': [{ 'key': key, 'val': val } for key, val in labels.items()], # 资源限制 'resources': container_spec.get('resources', {}), }
def get_k8s_desired_ready_instance_count(info, resource_name): """获取应用期望/正常的实例数量 """ filter_keys = constants.RESOURCE_REPLICAS_KEYS[resource_name] # 针对不同的模板获取不同key对应的值 ready_replicas = getitems(info, filter_keys['ready_replicas_keys'], default=0) desired_replicas = getitems(info, filter_keys['desired_replicas_keys'], default=0) return desired_replicas, ready_replicas
def update_or_create_custom_object(self, cobj_client): cobj_client.update_or_create(body=sample_custom_object, namespace="default", name=getitems(sample_custom_object, "metadata.name")) yield cobj_client.delete_wait_finished(name=getitems(sample_custom_object, "metadata.name"), namespace="default")
def format_dict(self, resource_dict: Dict) -> Dict: res = self.format_common_dict(resource_dict) res.update({ 'name': getitems(resource_dict, 'metadata.name'), 'scope': getitems(resource_dict, 'spec.scope'), 'kind': getitems(resource_dict, 'spec.names.kind'), 'api_version': parse_cobj_api_version(resource_dict), }) return res
def handle_application_log_config(self, application_id, container_name, resource_kind): """Application 中非标准日志采集""" # 获取业务的 dataid cc_app_id = self.context["SYS_CC_APP_ID"] application = MODULE_DICT.get(resource_kind).objects.get( id=application_id) self.resource_show_name = "%s-%s-%s" % ( application.name, container_name, LOG_CONFIG_MAP_SUFFIX) # 从Application 中获取日志路径 _item_config = application.get_config() containers = getitems(_item_config, ["spec", "template", "spec", "containers"], []) init_containers = getitems( _item_config, ["spec", "template", "spec", "initContainers"], []) log_path_list = [] for con_list in [init_containers, containers]: for _c in con_list: _c_name = _c.get("name") if _c_name == container_name: log_path_list = _c.get("logPathList") or [] break if not log_path_list: return {} # 生成 configmap 的内容 not_standard_data_id = self.context["SYS_NON_STANDARD_DATA_ID"] inners = [] for log_path in log_path_list: inners.append({ "logpath": log_path, "dataid": not_standard_data_id, "selectors": [] }) log_content = {"inners": inners, "mounts": []} log_key = "%s%s" % (application.name, LOG_CONFIG_MAP_KEY_SUFFIX) log_config = { "kind": "configmap", "metadata": { "name": self.resource_show_name } } if self.resource_name in ["configmap"]: log_config["datas"] = { log_key: { "type": "file", "content": json.dumps(log_content) } } else: log_config["data"] = {log_key: json.dumps(log_content)} return log_config
def delete(self, operator: str, resource_inst_id: int): resource_inst = models.ResourceInstance.objects.get( id=resource_inst_id) api = self._get_api(resource_inst.kind, getitems(resource_inst.manifest, 'apiVersion')) api.delete_ignore_nonexistent(name=resource_inst.name, namespace=getitems( resource_inst.manifest, 'metadata.namespace')) return resource_inst.delete()
def get_all_service(self): service_list = [] resp = self.api_instance.list_service_for_all_namespaces(_preload_content=False) data = json.loads(resp.data) for info in data.get('items') or []: resource_name = getitems(info, ['metadata', 'name'], '') resource_namespace = getitems(info, ['metadata', 'namespace'], '') item = self.render_resource(self.resource_kind, info, resource_name, resource_namespace) service_list.append(item) return service_list
def format_dict(self, resource_dict: Dict) -> Dict: labels = resource_dict.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 = resource_dict.get("metadata", {}).get("annotations") or {} namespace = resource_dict["metadata"]["namespace"] current_metrics = get_current_metrics(resource_dict) # k8s 注意需要调用 autoscaling/v2beta2 版本 api conditions = resource_dict["status"].get("conditions", []) conditions = sort_by_normalize_transition_time(conditions) data = { "cluster_id": self.cluster_id, "name": resource_dict["metadata"]["name"], "namespace": namespace, "max_replicas": resource_dict["spec"]["maxReplicas"], "min_replicas": resource_dict["spec"]["minReplicas"], "current_replicas": resource_dict["status"]["currentReplicas"], "current_metrics_display": get_current_metrics_display(current_metrics), "current_metrics": current_metrics, "conditions": conditions, "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, ""), "ref_name": getitems(resource_dict, "spec.scaleTargetRef.name", ""), "ref_kind": getitems(resource_dict, "spec.scaleTargetRef.kind", ""), } data["update_time"] = annotations.get( instance_constants.ANNOTATIONS_UPDATE_TIME, data["create_time"]) data["updator"] = annotations.get( instance_constants.ANNOTATIONS_UPDATOR, data["creator"]) return data
def validate_pod_selector(config): """检查 selector 是否在label中 """ spec = config.get('spec', {}) selector_labels = getitems(spec, ['selector', 'matchLabels']) if selector_labels: pod_labels = getitems(spec, ['template', 'metadata', 'labels'], default={}) if not set(selector_labels.items()).issubset(pod_labels.items()): invalid_label_list = ['%s:%s' % (x, pod_labels[x]) for x in pod_labels] invalid_label_str = "; ".join(invalid_label_list) raise ValidationError(f"[{invalid_label_str}]不在用户填写的标签中")
def filter_data(self, resource_type, resp_data, params): data_list = [] for resource in resp_data.get("items") or []: name = getitems(resource, ["metadata", "name"], "") namespace = getitems(resource, ["metadata", "namespace"], "") # filter data resource = self._get_resource(params, name, namespace, resource, resource_type) if resource: data_list.append(resource) return data_list
def list_namespace_quota(self, namespace: str) -> List: """获取命名空间下的所有资源配额""" quotas = self.api.get(namespace=namespace).to_dict() return [{ 'name': getitems(quota, 'metadata.name'), 'namespace': getitems(quota, 'metadata.namespace'), 'quota': { 'hard': getitems(quota, 'status.hard'), 'used': getitems(quota, 'status.used') }, } for quota in quotas['items']]
def get_all_ingress(self): ingress_list = [] resp = self.api_instance.list_ingress_for_all_namespaces(_preload_content=False) data = json.loads(resp.data) for info in data.get('items') or []: item = self.render_resource( 'Ingress', info, getitems(info, ['metadata', 'name'], ''), getitems(info, ['metadata', 'namespace'], '') ) ingress_list.append(item) return ingress_list
def get_k8s_category_info(self, request, project_id, resource_name, inst_name, cluster_id, ns_name): """获取分类的上报信息 {'BCS-K8S-15007': {'K8sDeployment': {'inst_list': ['bellke-test-deploy-1'], 'ns_list': ['abc1']}}} """ ret_data = {} client = K8SClient( request.user.token.access_token, project_id, cluster_id, None ) curr_func = FUNC_MAP[resource_name] % 'get' resp = retry_requests( getattr(client, curr_func), params={ "name": inst_name, "namespace": ns_name, "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 [] # 添加HPA绑定信息 data = get_deployment_hpa(request, project_id, cluster_id, ns_name, data) for info in data: spec = getitems(info, ['data', 'spec'], default={}) # 针对不同的模板获取不同的值 replicas, available = utils.get_k8s_desired_ready_instance_count(info, resource_name) curr_key = (info['namespace'], info['resourceName']) labels = getitems(info, ['data', 'metadata', 'labels'], default={}) source_type = labels.get('io.tencent.paas.source_type') or 'other' annotations = getitems(info, ['data', 'metadata', 'annotations'], default={}) ret_data[curr_key] = { 'backend_status': 'BackendNormal', 'backend_status_message': _('请求失败,已通知管理员!'), 'category': resource_name, 'pod_count': f'{available}/{replicas}', 'build_instance': available, 'instance': replicas, 'status': utils.get_k8s_resource_status(resource_name, info, replicas, available), 'name': info['resourceName'], 'namespace': info['namespace'], 'create_at': info['createTime'], 'update_at': info['updateTime'], 'source_type': SOURCE_TYPE_MAP.get(source_type), 'version': get_instance_version_name(annotations, labels), # 标识应用的线上版本 'hpa': info['hpa'] # 是否绑定了HPA } if spec.get('paused'): ret_data[curr_key]['status'] = 'Paused' return ret_data
def format_dict(self, resource_dict: Dict) -> NodeResourceData: addresses = getitems(resource_dict, ["status", "addresses"], []) # 获取IP inner_ip = "" for addr in addresses: if addr["type"] == "InternalIP": inner_ip = addr["address"] break name = getitems(resource_dict, ["metadata", "name"], "") return NodeResourceData(data=resource_dict, name=name, inner_ip=inner_ip)
def _parse_external_metric(self, idx: int, spec: Dict) -> str: """ 解析来源自 External 的指标信息 """ current = '<unknown>' if getitems(spec, 'external.target.averageValue') is not None: if len(self.statuses) > idx: ext_cur_avg_val = getitems(self.statuses[idx], 'external.current.averageValue') current = ext_cur_avg_val if ext_cur_avg_val else current return f"{current}/{getitems(spec, 'external.target.averageValue')} (avg)" else: if len(self.statuses) > idx: ext_cur_val = getitems(self.statuses[idx], 'external.current.value') current = ext_cur_val if ext_cur_val else current return f"{current}/{getitems(spec, 'external.target.value')}"
def _parse_object_metric(self, idx: int, spec: Dict) -> str: """ 解析来源自 Object 的指标信息 """ current = '<unknown>' if getitems(spec, 'object.target.averageValue') is not None: if len(self.statuses) > idx: obj_cur_avg_val = getitems(self.statuses[idx], 'object.current.averageValue') current = obj_cur_avg_val if obj_cur_avg_val else current return f"{current}/{getitems(spec, 'object.target.averageValue')} (avg)" else: if len(self.statuses) > idx: obj_cur_val = getitems(self.statuses[idx], 'object.current.value') current = obj_cur_val if obj_cur_val else current return f"{current}/{getitems(spec, 'object.target.value')}"
class TestCustomObject: """测试 CustomObject 相关接口""" crd_name = getitems(crd_manifest, 'metadata.name') cobj_name = getitems(cobj_manifest, 'metadata.name') batch_url = f'{DAU_PREFIX}/crds/v2/{crd_name}/custom_objects/' detail_url = f'{DAU_PREFIX}/crds/v2/{crd_name}/custom_objects/{cobj_name}/' def test_create(self, api_client): """测试创建资源接口""" response = api_client.post(self.batch_url, data={'manifest': cobj_manifest}) assert response.json()['code'] == 0 def test_list(self, api_client): """测试获取资源列表接口""" response = api_client.get(self.batch_url, data={'namespace': 'default'}) assert response.json()['code'] == 0 assert response.data['manifest']['kind'] == 'CronTab4TestList' def test_update(self, api_client): """测试更新资源接口""" # 修改 cronSpec cobj_manifest['spec']['cronSpec'] = '* * * * */5' response = api_client.put(self.detail_url, data={ 'manifest': cobj_manifest, 'namespace': 'default' }) assert response.json()['code'] == 0 def test_retrieve(self, api_client): """测试获取单个资源接口""" response = api_client.get(self.detail_url, data={'namespace': 'default'}) assert response.json()['code'] == 0 assert response.data['manifest']['kind'] == 'CronTab4Test' assert getitems(response.data, 'manifest.spec.cronSpec') == '* * * * */5' def test_destroy(self, api_client): """测试删除单个资源""" response = api_client.delete(self.detail_url + '?namespace=default') assert response.json()['code'] == 0 def test_list_shared_cluster_cobj(self, api_client, project_id): """获取共享集群 cobj,预期是被拦截(PermissionDenied)""" url = f'/api/dashboard/projects/{project_id}/clusters/{TEST_SHARED_CLUSTER_ID}/crds/v2/{self.crd_name}/custom_objects/' # noqa assert api_client.get(url).json()['code'] == 400
def get_service_by_namespace(self, params): resp = self.api_instance.list_namespaced_ingress(params['namespace'], _preload_content=False) data = json.loads(resp.data) ingress_list = [] for info in data.get('items') or []: resource_name = getitems(info, ['metadata', 'name'], '') item = self.render_resource( 'Ingress', info, resource_name, getitems(info, ['metadata', 'namespace'], '')) if params.get('name'): if resource_name == params['name']: ingress_list.append(item) break else: ingress_list.append(item) return ingress_list
def parse_v1beta1_rules(self, resource_dict: Dict) -> List: """ 解析 extensions/v1beta1 版本 Ingress Rules """ rules = [] for r in getitems(resource_dict, 'spec.rules', []): sub_rules = [ { 'host': get_with_placeholder(r, 'host'), 'path': get_with_placeholder(p, 'path'), 'serviceName': get_with_placeholder(p, 'backend.serviceName'), 'port': get_with_placeholder(p, 'backend.servicePort'), } for p in getitems(r, 'http.paths', []) ] rules.extend(sub_rules) return rules