Ejemplo n.º 1
0
    def fetch_host_ip_with_property_filter(self):
        """
        获取业务下过滤后的主机IP列表
        """
        for property_filter_type in self.PROPERTY_FILTER_TYPES:
            key = f"{property_filter_type}_property_filter"
            if not self.property_filters[key]["rules"]:
                self.property_filters.pop(key)

        host_info = cmdb.get_business_host_topo(
            self.username,
            self.bk_biz_id,
            self.bk_supplier_account,
            [
                "bk_host_id", "bk_host_innerip", "bk_host_outerip",
                "bk_host_name", "bk_cloud_id"
            ],
            property_filters=self.property_filters,
        )
        logger.info(
            "[fetch_host_info] cmdb.get_business_host_topo return: {host_info}"
            .format(host_info=host_info))

        host_info = self.format_host_info(host_info)
        return {
            "result": True,
            "code": NO_ERROR,
            "data": host_info,
            "message": ""
        }
Ejemplo n.º 2
0
    def test__get_with_ip_list(self):
        mock_batch_request = MagicMock(
            return_value=self.list_biz_hosts_topo_return)
        with patch("gcloud.utils.cmdb.batch_request", mock_batch_request):
            hosts_topo = get_business_host_topo(self.username, self.bk_biz_id,
                                                self.supplier_account,
                                                self.host_fields, self.ip_list)

        self.assertEqual(hosts_topo, self.get_business_host_topo_expect_return)
        mock_batch_request.assert_called_once_with(
            "list_biz_hosts_topo",
            {
                "bk_biz_id": self.bk_biz_id,
                "bk_supplier_account": self.supplier_account,
                "fields": self.host_fields,
                "host_property_filter": {
                    "condition":
                    "AND",
                    "rules": [{
                        "field": "bk_host_innerip",
                        "operator": "in",
                        "value": self.ip_list
                    }],
                },
            },
        )
Ejemplo n.º 3
0
def cc_get_inner_ip_by_module_id(username,
                                 biz_cc_id,
                                 module_id_list,
                                 supplier_account=0,
                                 host_fields=None):
    """根据模块列表过滤业务下主机

    :param username: 请求用户名
    :type username: str
    :param biz_cc_id: 业务 CC ID
    :type biz_cc_id: int
    :param module_id_list: 过滤模块 ID 列表
    :type module_id_list: list[int]
    :param supplier_account: 开发商账号, defaults to 0
    :type supplier_account: int, optional
    :param host_fields: 主机过滤字段, defaults to None
    :type host_fields: list[str], optional
    :return: [
        {
            "host": {
                "bk_host_id": 4,
                "bk_host_innerip": "127.0.0.1",
                "bk_cloud_id": 0,
                ...
            },
            "module": [
                {
                    "bk_module_id": 2,
                    "bk_module_name": "module_name"
                },
                ...
            ],
            "set": [
                {
                    "bk_set_name": "set_name",
                    "bk_set_id": 1
                },
                ...
            ]
        }
    ]
    :rtype: list
    """
    host_info_list = cmdb.get_business_host_topo(username, biz_cc_id,
                                                 supplier_account, host_fields)

    # filter host
    filtered = []
    target_modules = {int(mid) for mid in module_id_list}
    for host_info in host_info_list:
        parent_module_id_set = {m["bk_module_id"] for m in host_info["module"]}
        if target_modules.intersection(parent_module_id_set):
            filtered.append(host_info)

    return filtered
Ejemplo n.º 4
0
    def test__get_without_ip_list(self):
        mock_batch_request = MagicMock(
            return_value=self.list_biz_hosts_topo_return)
        with patch("gcloud.utils.cmdb.batch_request", mock_batch_request):
            hosts_topo = get_business_host_topo(self.username, self.bk_biz_id,
                                                self.supplier_account,
                                                self.host_fields)

        self.assertEqual(hosts_topo, self.get_business_host_topo_expect_return)
        mock_batch_request.assert_called_once_with(
            "list_biz_hosts_topo",
            {
                "bk_biz_id": self.bk_biz_id,
                "bk_supplier_account": self.supplier_account,
                "fields": self.host_fields
            },
        )
Ejemplo n.º 5
0
def cmdb_search_host(request, bk_biz_id, bk_supplier_account="", bk_supplier_id=0):
    """
    @summary: 获取 CMDB 上业务的 IP 列表,以及 agent 状态等信息
    @param request:
    @param bk_biz_id: 业务 CMDB ID
    @param bk_supplier_account: 业务开发商账号
    @param bk_supplier_id: 业务开发商ID
    @params fields: list 查询字段,默认只返回 bk_host_innerip、bk_host_name、bk_host_id, 可以查询主机的任意字段,也可以查询
                set、module、cloud、agent等信息
    @return:
    """
    default_host_fields = ["bk_host_id", "bk_host_name", "bk_cloud_id", "bk_host_innerip"]
    fields = set(default_host_fields + json.loads(request.GET.get("fields", "[]")))
    client = get_client_by_user(request.user.username)

    topo_modules_id = set()

    # get filter module id
    if request.GET.get("topo", None):
        topo = json.loads(request.GET.get("topo"))
        topo_result = get_cmdb_topo_tree(request.user.username, bk_biz_id, bk_supplier_account)
        if not topo_result["result"]:
            return JsonResponse(topo_result)

        biz_topo_tree = topo_result["data"][0]
        topo_dict = {}
        for tp in topo:
            topo_dict.setdefault(tp["bk_obj_id"], []).append(int(tp["bk_inst_id"]))
        topo_objects = get_objects_of_topo_tree(biz_topo_tree, topo_dict)
        topo_modules = []

        for obj in topo_objects:
            topo_modules += get_modules_of_bk_obj(obj)
        topo_modules_id = set(get_modules_id(topo_modules))

    cloud_area_result = client.cc.search_cloud_area({})
    if not cloud_area_result["result"]:
        message = handle_api_error(_("配置平台(CMDB)"), "cc.search_cloud_area", {}, cloud_area_result)
        result = {"result": False, "code": ERROR_CODES.API_GSE_ERROR, "message": message}
        return JsonResponse(result)

    raw_host_info_list = cmdb.get_business_host_topo(request.user.username, bk_biz_id, bk_supplier_account, fields)

    # map cloud_area_id to cloud_area
    cloud_area_dict = {}
    for cloud_area in cloud_area_result["data"]["info"]:
        cloud_area_dict[cloud_area["bk_cloud_id"]] = cloud_area

    # module filtered
    host_info_list = []
    if topo_modules_id:
        for host_info in raw_host_info_list:
            parent_module_id_set = {m["bk_module_id"] for m in host_info["module"]}
            if topo_modules_id.intersection(parent_module_id_set):
                host_info_list.append(host_info)
    else:
        host_info_list = raw_host_info_list

    data = []

    if host_info_list:
        for host in host_info_list:
            host_detail = {field: host["host"][field] for field in fields if field in host["host"]}
            host_detail["bk_host_innerip"] = format_sundry_ip(host_detail["bk_host_innerip"])
            if "set" in fields:
                host_detail["set"] = host["set"]
            if "module" in fields:
                host_detail["module"] = host["module"]
            if "cloud" in fields or "agent" in fields:
                cloud_id = host["host"].get("bk_cloud_id")
                host_detail["cloud"] = [
                    {"id": str(cloud_id), "bk_inst_name": cloud_area_dict.get(cloud_id, {}).get("bk_cloud_name", "")}
                ]
            data.append(host_detail)

        if "agent" in fields:
            agent_kwargs = {
                "bk_biz_id": bk_biz_id,
                "bk_supplier_id": bk_supplier_id,
                "hosts": [
                    {"bk_cloud_id": host["bk_cloud_id"], "ip": host["bk_host_innerip"]}
                    for host in data
                    if host["bk_host_innerip"] != ""
                ],
            }
            agent_result = client.gse.get_agent_status(agent_kwargs)
            if not agent_result["result"]:
                message = handle_api_error(_("管控平台(GSE)"), "gse.get_agent_status", agent_kwargs, agent_result)
                result = {"result": False, "code": ERROR_CODES.API_GSE_ERROR, "message": message}
                return JsonResponse(result)

            agent_data = agent_result["data"]
            for host in data:
                # agent在线状态,0为不在线,1为在线,-1为未知
                agent_info = agent_data.get(
                    "{cloud}:{ip}".format(cloud=host["bk_cloud_id"], ip=host["bk_host_innerip"]), {}
                )
                host["agent"] = agent_info.get("bk_agent_alive", -1)

        # search host lock status
        if request.GET.get("search_host_lock", None):
            bk_host_id_list = [host_detail["bk_host_id"] for host_detail in data]
            host_lock_status_result = client.cc.search_host_lock({"id_list": bk_host_id_list})
            if not host_lock_status_result["result"]:
                message = handle_api_error(_("配置平台(CMDB)"), "cc.search_host_lock", {}, host_lock_status_result)
                result = {"result": False, "code": ERROR_CODES.API_GSE_ERROR, "message": message}
                return JsonResponse(result)
            host_lock_status_data = {int(k): v for k, v in host_lock_status_result["data"].items()}
            for host_detail in data:
                host_lock_status = host_lock_status_data.get(host_detail["bk_host_id"])
                if host_lock_status is not None:
                    host_detail["bk_host_lock_status"] = host_lock_status
    result = {"result": True, "code": NO_ERROR, "data": data}
    return JsonResponse(result)
Ejemplo n.º 6
0
    def execute(self, data, parent_data):
        executor = parent_data.get_one_of_inputs("executor")

        client = get_client_by_user(executor)
        if parent_data.get_one_of_inputs("language"):
            setattr(client, "language",
                    parent_data.get_one_of_inputs("language"))
            translation.activate(parent_data.get_one_of_inputs("language"))

        biz_cc_id = data.get_one_of_inputs("biz_cc_id",
                                           parent_data.inputs.biz_cc_id)
        supplier_account = supplier_account_for_business(biz_cc_id)
        cc_hosts = data.get_one_of_inputs("cc_host_replace_detail")
        copy_attrs = data.get_one_of_inputs("copy_attributes", True)

        # 查询主机可编辑属性
        search_attr_kwargs = {
            "bk_obj_id": "host",
            "bk_supplier_account": supplier_account
        }
        search_attr_result = client.cc.search_object_attribute(
            search_attr_kwargs)
        if not search_attr_result["result"]:
            message = cc_handle_api_error("cc.search_object_attribute",
                                          search_attr_kwargs,
                                          search_attr_result)
            self.logger.error(message)
            data.outputs.ex_data = message
            return False

        editable_attrs = []
        for item in search_attr_result["data"]:
            if item["editable"]:
                editable_attrs.append(item["bk_property_id"])

        # 拉取所有主机信息
        fault_replace_ip_map = {}
        for item in cc_hosts:
            fault_replace_ip_map["".join(get_ip_by_regex(
                item["cc_fault_ip"]))] = "".join(
                    get_ip_by_regex(item["cc_new_ip"]))

        all_hosts = []
        all_hosts.extend(list(fault_replace_ip_map.keys()))
        all_hosts.extend(list(fault_replace_ip_map.values()))

        host_attrs = editable_attrs + ["bk_host_innerip"]
        hosts_topo = cmdb.get_business_host_topo(executor, biz_cc_id,
                                                 supplier_account, host_attrs,
                                                 all_hosts)

        if not hosts_topo:
            data.outputs.ex_data = "fetch host topo for {} failed".format(
                all_hosts)
            return False

        # 只有复制故障机属性时才用到
        batch_update_kwargs = {
            "bk_obj_id": "host",
            "bk_supplier_account": supplier_account,
            "update": []
        }

        host_dict = {
            host_info["host"]["bk_host_innerip"]: host_info["host"]
            for host_info in hosts_topo
        }
        host_id_to_ip = {
            host_info["host"]["bk_host_id"]:
            host_info["host"]["bk_host_innerip"]
            for host_info in hosts_topo
        }
        fault_replace_id_map = {}

        for fault_ip, new_ip in list(fault_replace_ip_map.items()):
            fault_host = host_dict.get(fault_ip)
            new_host = host_dict.get(new_ip)

            if not fault_host:
                data.outputs.ex_data = _(
                    "无法查询到 %s 机器信息,请确认该机器是否在当前业务下") % fault_ip
                return False

            if not new_host:
                data.outputs.ex_data = _(
                    "无法查询到 %s 机器信息,请确认该机器是否在当前业务下") % new_ip
                return False

            if copy_attrs:
                update_item = {
                    "properties": {},
                    "bk_host_id": new_host["bk_host_id"]
                }
                for attr in [
                        attr for attr in editable_attrs if attr in fault_host
                ]:
                    update_item["properties"][attr] = fault_host[attr]
                batch_update_kwargs["update"].append(update_item)

            fault_replace_id_map[
                fault_host["bk_host_id"]] = new_host["bk_host_id"]

        # 更新替换机信息
        if copy_attrs:
            update_result = client.cc.batch_update_host(batch_update_kwargs)
            if not update_result["result"]:
                message = cc_handle_api_error("cc.batch_update_host",
                                              batch_update_kwargs,
                                              update_result)
                self.logger.error(message)
                data.outputs.ex_data = message
                return False

        # 将主机上交至故障机模块
        fault_transfer_kwargs = {
            "bk_supplier_account": supplier_account,
            "bk_biz_id": biz_cc_id,
            "bk_host_id": list(fault_replace_id_map.keys()),
        }
        fault_transfer_result = client.cc.transfer_host_to_faultmodule(
            fault_transfer_kwargs)
        if not fault_transfer_result["result"]:
            message = cc_handle_api_error("cc.transfer_host_to_faultmodule",
                                          fault_transfer_kwargs,
                                          fault_transfer_result)
            self.logger.error(message)
            data.set_outputs("ex_data", message)
            return False

        # 转移主机模块
        transfer_kwargs_list = []
        for host_info in hosts_topo:
            new_host_id = fault_replace_id_map.get(
                host_info["host"]["bk_host_id"])

            if new_host_id:
                transfer_kwargs_list.append({
                    "bk_biz_id":
                    biz_cc_id,
                    "bk_supplier_account":
                    supplier_account,
                    "bk_host_id": [new_host_id],
                    "bk_module_id": [
                        module_info["bk_module_id"]
                        for module_info in host_info["module"]
                    ],
                    "is_increment":
                    True,
                })

        success = []
        for kwargs in transfer_kwargs_list:
            transfer_result = client.cc.transfer_host_module(kwargs)
            if not transfer_result["result"]:
                message = cc_handle_api_error("cc.transfer_host_module",
                                              kwargs, transfer_result)
                self.logger.error(message)
                data.outputs.ex_data = "{msg}\n{success}".format(
                    msg=message, success=_("成功替换的机器: %s") % ",".join(success))
                return False

            success.append(host_id_to_ip[kwargs["bk_host_id"][0]])
Ejemplo n.º 7
0
def cc_get_ips_info_by_str(username, biz_cc_id, ip_str, use_cache=True):
    """
    @summary: 从ip_str中匹配出IP信息
    @param username
    @param biz_cc_id
    @param ip_str
    @param use_cache(deprecated)
    @note: 需要兼容的ip_str格式有
        1: IP,纯IP格式
        2: 集群名称|模块名称|IP,集群名称|模块名称|IP  这种格式可以唯一定位到一
            个IP(如果业务把相同IP放到同一模块,还是有问题)
        3: 云区域ID:IP,云区域ID:IP  这种格式可以唯一定位到一个IP,主要是兼容Job组件
            传参需要和获取Job作业模板步骤参数
    @return: {'result': True or False, 'data': [{'InnerIP': ,'HostID': ,
        'Source': , 'SetID': , 'SetName': , 'ModuleID': , 'ModuleName': , 'Sets': , 'Module': },{}]}
    """

    ip_input_list = get_ip_by_regex(ip_str)

    supplier_account = supplier_account_for_business(biz_cc_id)

    ip_list = cmdb.get_business_host_topo(
        username=username,
        bk_biz_id=biz_cc_id,
        supplier_account=supplier_account,
        host_fields=["bk_host_innerip", "bk_host_id", "bk_cloud_id"],
        ip_list=ip_input_list,
    )
    ip_result = []

    # 如果是格式2 集群名称|模块名称|IP,暂时不支持这种格式bk_host_innerip有多个值的情况
    if set_module_ip_reg.match(ip_str):
        set_module_ip_list = []
        for match in set_module_ip_reg.finditer(ip_str):
            set_module_ip_list.append(match.group())

        for ip_info in ip_list:
            match = False
            for parent_set in ip_info["set"]:
                if match:
                    break

                for parent_module in ip_info["module"]:
                    if match:
                        break

                    topo_ip = "{set}|{module}|{ip}".format(
                        set=parent_set["bk_set_name"],
                        module=parent_module["bk_module_name"],
                        ip=ip_info["host"].get("bk_host_innerip", ""),
                    )

                    if topo_ip in set_module_ip_list:
                        match = True
                        ip_result.append({
                            "InnerIP":
                            ip_info["host"].get("bk_host_innerip", ""),
                            "HostID":
                            ip_info["host"]["bk_host_id"],
                            "Source":
                            ip_info["host"].get("bk_cloud_id", -1),
                            "SetID":
                            parent_set["bk_set_id"],
                            "SetName":
                            parent_set["bk_set_name"],
                            "ModuleID":
                            parent_module["bk_module_id"],
                            "ModuleName":
                            parent_module["bk_module_name"],
                            "Sets":
                            ip_info["set"],
                            "Modules":
                            ip_info["module"],
                        })

    # 格式3 云区域ID:IP
    elif plat_ip_reg.match(ip_str):
        plat_ip = []
        for match in plat_ip_reg.finditer(ip_str):
            plat_ip.append(match.group())

        for ip_info in ip_list:
            valid_hosts = [
                x
                for x in ip_info["host"].get("bk_host_innerip", "").split(",")
                if x
                and f'{ip_info["host"].get("bk_cloud_id", -1)}:{x}' in plat_ip
            ]
            if valid_hosts:
                ip_result.append({
                    "InnerIP":
                    valid_hosts[0],  # 即使多个host命中,也都是同一个主机id,这里以第一个合法host为标识
                    "HostID":
                    ip_info["host"]["bk_host_id"],
                    "Source":
                    ip_info["host"].get("bk_cloud_id", -1),
                    "Sets":
                    ip_info["set"],
                    "Modules":
                    ip_info["module"],
                })

    # 格式1 纯IP格式
    else:
        ip = []
        for match in ip_pattern.finditer(ip_str):
            ip.append(match.group())

        proccessed = set()
        for ip_info in ip_list:
            valid_hosts = [
                x
                for x in ip_info["host"].get("bk_host_innerip", "").split(",")
                if x and x in ip
            ]
            if valid_hosts and ip_info["host"]["bk_host_id"] not in proccessed:
                ip_result.append({
                    "InnerIP":
                    valid_hosts[0],  # 即使多个host命中,也都是同一个主机id,这里以第一个合法host为标识
                    "HostID":
                    ip_info["host"]["bk_host_id"],
                    "Source":
                    ip_info["host"].get("bk_cloud_id", -1),
                    "Sets":
                    ip_info["set"],
                    "Modules":
                    ip_info["module"],
                })
                proccessed.add(ip_info["host"]["bk_host_id"])

    valid_ip = [ip_info["InnerIP"] for ip_info in ip_result]
    invalid_ip = list(set(ip_input_list) - set(valid_ip))
    result = {
        "result": True,
        "ip_result": ip_result,
        "ip_count": len(ip_result),
        "invalid_ip": invalid_ip,
    }
    return result