예제 #1
0
    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
예제 #2
0
    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())
예제 #3
0
    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
예제 #4
0
 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,
     }
예제 #5
0
 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)
예제 #6
0
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
예제 #7
0
    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
예제 #8
0
    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)
예제 #9
0
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
예제 #10
0
 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
예제 #11
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
예제 #12
0
    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', {}),
        }
예제 #13
0
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
예제 #14
0
 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")
예제 #15
0
 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
예제 #16
0
    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
예제 #17
0
 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()
예제 #18
0
 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
예제 #19
0
    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
예제 #20
0
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}]不在用户填写的标签中")
예제 #21
0
    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
예제 #22
0
 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']]
예제 #23
0
 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
예제 #24
0
    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
예제 #25
0
    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)
예제 #26
0
 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')}"
예제 #27
0
 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')}"
예제 #28
0
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
예제 #29
0
 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
예제 #30
0
 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