# -*- coding:utf-8 -*-
# Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved.
import json
import os
import re
import threading
import time
import traceback

from platforms.project.ProjectUtils import get_project_condition_boolean
from platforms.taskcenter.install_os_lib import InstallOs
from utils.DBAdapter.DBConnector import BaseOps
import utils.common.log as logger
from utils.business.project_util import ProjectApi
from utils.common import network_pci_slot_mapping_util
from utils.common.exception import FCDException
from utils.common.ssh_util import Ssh as ssh
from utils.odkApi.odkApi import OdkApi
from utils.security.crypt import decrypt
from plugins.AC.scripts.ApiAdapter import API
from plugins.ResourceCheck.libs.ibmc_cmd_libs import IBMCOperate
from plugins.DistributedStorage.scripts.utils.common.DeployConstant import DeployConstant
from plugins.DistributedStorage.scripts.utils.common.separate_storage_node_check_network import ping_all_ip
from plugins.DistributedStorage.scripts.utils.common.euler_conf import X86Euler, ARMEuler, PublicItems


INSTALL_STATUS_COMPLETED = (3, 4)
INSTALL_STATUS_SUCCESS = 3
INSTALL_STATUS_FAIL = 4
INSTALL_STATUS_MAPPING_SUC = 10
INSTALL_STATUS_MAPPING_FAILED = 9
INSTALL_STATUS_PAUSE = 5
INSTALL_STATUS_MAPPING_STOP = 4
INSTALL_STATUS_MAPPING_INIT = 0


class InstallOS(object):
    def __init__(self, project_id, pod_id, fs_args, process="norep"):
        self.project_id = project_id
        self.pod_id = pod_id
        self.db = BaseOps()
        self.process = process
        self.wait_ping_node_list = list()
        self.is_mixed = get_project_condition_boolean(
            self.project_id,
            "(CSHAStorage_TFB|CSDRStorage_TFB)&!DRStorage_TFB_Sep")
        self.bmc_condition = get_project_condition_boolean(
            self.project_id,
            'TenantStorFB80&(CascadedOpenStack_BMS|ExpansionPod_BMS)')
        self.csha_condition = get_project_condition_boolean(
            self.project_id, "CSHAStorage_TFB")

        if self.process == "rep":
            self.bmc_info_list = InstallOs.get_waitting_bmc_install_list(
                self.project_id, self.pod_id, ["rep", "rep_ctl"])
        else:
            if self.is_mixed:
                self.bmc_info_list = InstallOs.get_waitting_bmc_install_list(
                    self.project_id, self.pod_id,
                    ["osd", "osd,rep", "osd,rep_ctl"])
            else:
                self.bmc_info_list = InstallOs.get_waitting_bmc_install_list(
                    self.project_id, self.pod_id, ["osd"])

        self.bmc_info_map = dict()
        for bmc_ip_info in self.bmc_info_list:
            self.bmc_info_map[bmc_ip_info["bmc_ip"]] = bmc_ip_info

        # 获取存储网口名称
        self.storage_interface_name = DeployConstant.MGR_STORAGE_NET_INTF
        self.project_info = self.db.get_project_info(self.project_id)
        if "Type1" == self.project_info.get('region_type', ''):
            if self.bmc_condition:
                # 新建pod为BMS场景下存储平面名
                self.storage_interface_name = "fsb_data0"

        self.net_infos = fs_args.get("net_infos")
        logger.info("net_infos: %s" % self.net_infos)
        self.fs_mgr_netmask = self.db.get_user_input_cloud_param_by_key(
            self.project_id, 'fusionstorage_manage_netmask')
        self.fs_mgr_gw = self.db.get_user_input_cloud_param_by_key(
            self.project_id, 'fusionstorage_manage_gateway')
        self.fs_mgr_vlan = self.db.get_user_input_cloud_param_by_key(
            self.project_id, 'fusionstorage_manage_vlan')
        self.fs_stg_netmask = self.db.get_user_input_cloud_param_by_key(
            self.project_id, 'fusionstorage_service_netmask')
        self.fs_stg_gw = self.db.get_user_input_cloud_param_by_key(
            self.project_id, 'fusionstorage_service_gateway')
        self.fs_stg_vlan = self.db.get_user_input_cloud_param_by_key(
            self.project_id, 'fusionstorage_service_vlan')
        self.iscsi_interface_name = "iscsi_business_plane"
        logger.info("Storage net port is %s" % self.storage_interface_name)
        self.odk_api = None

    @staticmethod
    def list_of_groups(init_list, children_list_len):
        list_of_groups = list(zip(*(iter(init_list),) * children_list_len))
        end_list = [list(i) for i in list_of_groups]
        count = len(init_list) % children_list_len
        end_list.append(init_list[-count:]) if count != 0 else end_list
        return end_list

    @staticmethod
    def is_same_list(src, dst):
        return list(set(src).difference(set(dst)))

    @staticmethod
    def get_os_template_by_args(package_arch):
        os_file_pre = "OceanStor-Pacific_"
        os_file_suffix = ".iso"
        msg = "Get the os template[OceanStor-Pacific_ %s] path"
        logger.info(msg % package_arch)
        os_file_path, os_template = API.find_file(os_file_pre, os_file_suffix, package_arch)
        logger.info("search result; os_file_path:%s, os_template:%s" % (os_file_path, os_template))
        if os_template == "":
            os_file_suffix = ".tgz"
            zippath, zipname = API.find_file(os_file_pre, os_file_suffix, package_arch)
            if zipname == "":
                return False, ''
            file_path = os.path.join(zippath, zipname)
            logger.info('Decompress the installation package:{}'.format(zipname))
            API.extract_file(file_path, "/home/pkg/")
            logger.info(msg % package_arch)
            os_file_path, os_template = API.find_file(os_file_pre, "iso", package_arch)
            logger.info("search again result; os_file_path:%s, os_template:%s" % (os_file_path, os_template))
            if not os_template:
                logger.error('Do not find os template file[{}8.*{}]'.format(os_file_pre, package_arch))
                raise FCDException(626024, os_file_pre + '8.1.*x86*64*' + os_file_suffix)
        os_template = os.path.splitext(os_template)[0]
        logger.info("Succeed to get os template file[%s]" % os_template)
        return True, os_template

    @staticmethod
    def get_os_version(server_arch, os_template):
        logger.info("Get pre script by arch[%s] and OS templage[%s]" % (
            server_arch, os_template))
        package_arch = "x86-64"
        if 'ARM' == server_arch:
            package_arch = "aarch64"
        ret_version_list = re.findall(
            r'{}.*SP\d+'.format("OS"), os_template)
        if len(ret_version_list) == 1:
            ret_version = ret_version_list[0]
        else:
            err_msg = "Failed get version from OS template[%s]" % os_template
            logger.error(err_msg)
            raise Exception(err_msg)
        os_version = ret_version.replace('OS-{}_'.format(package_arch), '') \
            .replace('OS-V', '').replace('OS', '')
        os_version = ("EulerOS" + os_version).lower()
        logger.info("Operating system version:%s" % os_version)
        return os_version

    @staticmethod
    def get_pre_script(server_arch, bmc_info):
        bmc_ip = bmc_info.get('bmc_ip')
        bmc_user = bmc_info.get('bmc_name')
        bmc_passwd = bmc_info.get('bmc_passwd')
        raid_alarm_id = "0x06000025"
        raid_health_flag = IBMCOperate(bmc_ip, bmc_user,
                                       bmc_passwd).check_health_event(
            raid_alarm_id)
        if raid_health_flag:
            err_msg = "node[%s] communicate with raid card failed" % bmc_ip
            logger.error(err_msg)
            raise FCDException(626276, err_msg)

        if server_arch == 'ARM':
            ks_pre_script = ARMEuler.ks_script()
        else:
            ks_pre_script = X86Euler.ks_script()
        return ks_pre_script

    @staticmethod
    def get_install_soft(server_arch):
        install_soft = {
            "X86": {"packages": X86Euler.euler_install_packages()},
            "ARM": {"packages": ARMEuler.euler_install_packages()}
        }
        return install_soft.get(server_arch)

    @staticmethod
    def get_pci_by_slot(bmc_ip, slot_list):
        pci_list = list()
        port_list = list()
        for slot in slot_list:
            pci, port = network_pci_slot_mapping_util.NicPciCls \
                .get_nic_pci_and_pid_by_slot_from_conf(bmc_ip, slot)
            if isinstance(pci, list):
                pci = '_'.join(pci)
            if pci:
                pci_list.append(pci)
            if port:
                port_list.append(port)
        if len(pci_list) == 0:
            err_msg = ("Failed to query the PCI number corresponding to the"
                       " slot number. Check whether the hardware check"
                       " is successful.")
            logger.info(err_msg)
            raise Exception(err_msg)
        return pci_list, port_list

    @staticmethod
    def get_raid_controller_ids(bmc_info):
        """
        :return:list of controller ids
        """
        bmc_ip = bmc_info.get('bmc_ip')
        bmc_user = bmc_info.get('bmc_name')
        bmc_passwd = bmc_info.get('bmc_passwd')
        ssh_client = ssh.ssh_create_client(bmc_ip, bmc_user, bmc_passwd)

        cmd_raid = 'ipmcget -t storage -d ctrlinfo -v all'
        ret_raid = ssh.ssh_send_command(ssh_client, cmd_raid, 'RAID', 30)
        logger.info("Run cmd[%s], result: %s" % (cmd_raid, ' '.join(ret_raid)))
        controller_id = ''
        controller_id_list = list()
        try:
            for output in ret_raid:
                if 'RAID Controller #' in output:
                    controller_id = output.split(' ')[2].replace('#', '')
                    continue
                if 'Controller Name' in output and controller_id:
                    controller_model = output.strip().split(' ')[-1]
                    logger.info('Found controller: %s, id %s' %
                                (controller_model, controller_id))
                    controller_id_list.append(controller_id)
                    break
        except Exception as e:
            logger.error('Check RAID for  %s failed' % bmc_ip)
            logger.error('Output %s' % str(e))
            ssh.ssh_close(ssh_client)
        return controller_id_list

    @staticmethod
    def _get_ip_info_for_config_os_net(net_info, ip_addr, pci_list, port_list):
        ip_info = dict()
        for (key, value) in net_info.items():
            if key == "plane" or key == "index":
                continue
            elif key == "ip_name":
                ip_info["ip_addr"] = ip_addr
            elif key == "nic_pci":
                ip_info[key] = ",".join(pci_list)
            elif key == "dev_port":
                ip_info[key] = ",".join(port_list)
            else:
                ip_info[key] = value
        return ip_info

    def procedure(self):
        if not self.bmc_info_list:
            logger.error("Separate storage node install OS error,"
                         " no bmc info.")
            raise FCDException("626031")
        bmc_ip_list = [bmc_info["bmc_ip"] for bmc_info in self.bmc_info_list]

        logger.info("Initializing ODK service")
        self.odk_api = OdkApi(self.project_id, self.pod_id)

        try:
            sn_lst = self.get_install_os_device_infos()
        except Exception as e:
            self.set_install_os_all_failed(bmc_ip_list)
            raise e

        threados = threading.Thread(target=self.call_install_os_api,
                                    name=threading.current_thread().name,
                                    args=(sn_lst,))
        logger.info("Start to exec installOperatingSystem.")
        threados.start()

        thread_ping = threading.Thread(target=self.check_install_os_network,
                                       name=threading.current_thread().name,
                                       args=([bmc_info["bmc_ip"] for bmc_info in self.bmc_info_list],))
        logger.info("Start to exec checkInstallOSNetwork.")
        thread_ping.start()

        logger.info("Start to exec waiting_install_os_to_end.")
        try:
            self.waiting_install_os_to_end(bmc_ip_list)
        except Exception as e:
            self.set_install_os_all_failed(bmc_ip_list)
            raise e
        finally:
            threados.join()
            thread_ping.join()
        logger.info("All nodeOS installation complete.")

    def get_os_template(self, server_arch='X86'):
        os_file_pre = "OceanStor-Pacific_"
        os_file_suffix = ".iso"
        package_arch = ["_aarch64", "OS-aarch64", "_x86-64", "OS-x86-64"]
        if server_arch == 'ARM':
            # 810/811版本号：OS-aarch64，812版本号：_aarch64
            res, os_template = self.get_os_template_by_args(package_arch[0])
            if not res:
                res, os_template = self.get_os_template_by_args(package_arch[1])
            if not res:
                err_msg = "Do not find os template file[{}8.*{}]".format(os_file_pre, package_arch)
                logger.error(err_msg)
                raise FCDException(626024, os_file_pre + '8.1.*aarch64' + os_file_suffix)
        else:
            # 810/811版本号：OS-x86-64，812版本号：_x86-64
            res, os_template = self.get_os_template_by_args(package_arch[2])
            if not res:
                res, os_template = self.get_os_template_by_args(package_arch[3])
            if not res:
                err_msg = "Do not find os template file[{}8.*{}]".format(os_file_pre, package_arch)
                logger.error(err_msg)
                raise FCDException(626024, os_file_pre + '8.1.*x86*64*' + os_file_suffix)
        logger.info("Succeed to get os template file[%s]" % os_template)
        return os_template

    def reset_status(self):
        if self.process == "rep":
            deploy_component = ["rep", "rep_ctl"]
        else:
            if self.is_mixed:
                deploy_component = ["osd", "osd,rep", "osd,rep_ctl"]
            else:
                deploy_component = ["osd"]

        InstallOs.reset_all_os_install_status(
            self.project_id, self.pod_id, deploy_component,
            INSTALL_STATUS_MAPPING_INIT)
        logger.info("install os rollback success.")

    def call_install_os_api(self, sn_lst):
        try:
            self.odk_api.installOperatingSystem(sn_lst)
        except Exception as e:
            logger.error("callInstallOSApi,Error occurs during install OS．"
                         "Detail: %s ,Uncompleted device list : %s." %
                         (str(e), list(self.bmc_info_map.keys())))
            logger.error(traceback.format_exc())
            raise e

    def check_install_os_network(self, bmc_ip_list):
        time.sleep(600)
        try:
            self._check_install_os_network(bmc_ip_list)
        except Exception as e:
            self.set_install_os_all_failed(bmc_ip_list)
            logger.error("Error occurs during network check.Detail: %s,"
                         "Uncompleted device list : %s."
                         % (str(e), list(self.bmc_info_map.keys())))
            logger.error(traceback.format_exc())
            raise e

    def ping_all_ip_to_end(self):
        success_ip_set = set()
        all_bmcip_set = set([bmc_ip_info['bmc_ip'] for bmc_ip_info in self.wait_ping_node_list])
        num = 0
        while num < 45:
            logger.info("Try to check node%s at %s times."
                        % (list(all_bmcip_set), num))
            temp_success_ip_list = []
            success_bmcip_lst = ping_all_ip(self.wait_ping_node_list,
                                            self.fs_stg_gw)
            for success_ip_info in success_bmcip_lst:
                if success_ip_info["bmc_ip"] in self.bmc_info_map:
                    self.bmc_info_map.pop(success_ip_info["bmc_ip"])
                temp_success_ip_list.append(success_ip_info["bmc_ip"])
                if success_ip_info in self.wait_ping_node_list:
                    self.wait_ping_node_list.remove(success_ip_info)
            logger.info("check success list%s at this %s time"
                        % (temp_success_ip_list, num))
            success_ip_set = success_ip_set | set(temp_success_ip_list)
            logger.info("all success list:%s at this %s time"
                        % (list(success_ip_set), num))
            time.sleep(10)
            num += 1
            if 0 == len(self.wait_ping_node_list):
                break
        fail_ip_set = all_bmcip_set - success_ip_set
        # 清空失败节点
        self.wait_ping_node_list = list()
        logger.info("check result, all:%s, success:%s, fail:%s."
                    % (list(all_bmcip_set), list(success_ip_set),
                       list(fail_ip_set)))
        return list(success_ip_set), list(fail_ip_set)

    def set_install_os_all_failed(self, bmc_ip_list):
        for bmc_ip in bmc_ip_list:
            InstallOs.update_os_install_status(
                self.project_id, self.pod_id, bmc_ip,
                status=INSTALL_STATUS_MAPPING_FAILED)

    def get_install_os_device_infos(self):
        ip_type_is_ipv6 = ProjectApi().is_ipv6_project(self.project_id)
        logger.info("Network type:%s" % ip_type_is_ipv6)
        grub_passwd = self.db.get_value_from_cloudparam(
            self.pod_id, "DistributedStorage", "KSGrubPassword")
        device_lst = list()
        json_path = r'/opt/FusionCloudDeploy/FusionCloudDeploy/plugins/ResourceCheck/scripts/' \
                    r'FusionStorage800/common/distributed_storage_node_cpu_arch.json'
        with open(json_path, 'r', encoding='utf-8') as cpu_file:
            cpu_arch_dict = json.load(cpu_file)
        for sub_bmc_info in self.bmc_info_list:
            bmc_ip = sub_bmc_info.get("bmc_ip")
            cpu_arch = cpu_arch_dict.get(bmc_ip).get('stdout')
            os_template = self.get_os_template(cpu_arch)
            logger.info("Currently node installing: CPU architecture[%s],"
                        " OS template[%s]" % (cpu_arch, os_template))
            os_version = self.get_os_version(cpu_arch, os_template)
            creuser_info = decrypt(sub_bmc_info.get('creuser')).split(',')
            logger.info("install os for (%s) by odk." % sub_bmc_info['bmc_ip'])
            device_info = {
                "bmcIp": sub_bmc_info['bmc_ip'],
                "bmcUser": sub_bmc_info['bmc_name'],
                "bmcPwd": sub_bmc_info['bmc_passwd'],
                "hostName": sub_bmc_info['hostname'],
                "cpuArch": cpu_arch,
                "startMode": "UEFI",
                "osType": "EULER",
                "ipType": "IPV6" if ip_type_is_ipv6 else "IPV4",
                "serverType": sub_bmc_info.get('equipment_model'),
                "osTemplate": os_template,
                "rootUser": {'username': creuser_info[0], 'password': creuser_info[1]},
                "generalUser": [{'username': creuser_info[2], 'password': creuser_info[3]}],
                "businessIp": self._get_business_ip(sub_bmc_info),
                "autoPartition": False,
                "postScripts": PublicItems.get_post_script(cpu_arch),
                "preScripts": self.get_pre_script(cpu_arch, sub_bmc_info).replace(
                    '{grub_passwd}', grub_passwd),
                "addon": '''com_huawei_grub_safe --iscrypted --password='%s' ''' % grub_passwd,
                "preInclude": ['/root/part-include'],
                "softwareNames": self.get_install_soft(cpu_arch)
            }
            if not ip_type_is_ipv6:
                device_info["businessGateway"] = self.fs_mgr_gw
            device_lst.append(device_info)
        logger.info("start to add device.")
        device_group = self.list_of_groups(device_lst, 40)
        sn_lst = []
        for device in device_group:
            child_sn_lst = self.odk_api.addDevice(device)
            sn_lst += child_sn_lst
        return sn_lst

    def waiting_install_os_to_end(self, bmc_ip_lst):
        install_failed_lst = []
        while True:
            time.sleep(60)
            logger.info("Waiting for installation to end, bmcIp:%s", bmc_ip_lst)
            device_info_lst = self.db.get_device(bmc_ip_lst)
            for device_info in device_info_lst:
                bmc_ip = device_info["bmcip"]
                exe_status = device_info.get("installstatus")
                logger.info("Device %s install_status: %s" % (bmc_ip, exe_status))
                if exe_status in INSTALL_STATUS_COMPLETED:
                    self._install_completed_handle(bmc_ip_lst, device_info, install_failed_lst)
                elif exe_status == INSTALL_STATUS_PAUSE:
                    bmc_ip_lst.remove(bmc_ip)
                    InstallOs.update_os_install_status(
                        self.project_id,
                        self.pod_id, bmc_ip,
                        device_info["installstarttime"],
                        device_info["installendtime"],
                        INSTALL_STATUS_MAPPING_STOP,
                        device_info["failreason"]
                    )
                else:
                    InstallOs.update_os_install_status(
                        self.project_id,
                        self.pod_id, bmc_ip,
                        device_info["installstarttime"],
                        device_info["installendtime"],
                        exe_status,
                        device_info["failreason"])

            if not bmc_ip_lst:
                break
            time.sleep(60)
        if install_failed_lst:
            raise FCDException(626082, str(install_failed_lst))

    def get_nic_mode(self, lld_key):
        nic_mode = self.db.get_user_input_cloud_param_by_key(self.project_id,
                                                             lld_key)
        logger.info("Get nic mode:%s" % nic_mode)
        if nic_mode == 'active_standby':
            bond_mode = 1
        elif nic_mode == 'lacp':
            bond_mode = 4
        else:
            bond_mode = 1
        logger.info("bond mode:%s" % bond_mode)
        return bond_mode

    def _install_completed_handle(self, bmc_ip_lst, device_info, install_failed_lst):
        bmc_ip = device_info.get("bmcip")
        exe_status = device_info.get("installstatus")
        bmc_ip_lst.remove(bmc_ip)
        if exe_status == INSTALL_STATUS_FAIL:
            InstallOs.update_os_install_status(
                self.project_id,
                self.pod_id,
                bmc_ip,
                device_info["installstarttime"],
                device_info["installendtime"],
                INSTALL_STATUS_MAPPING_FAILED,
                device_info["failreason"]
            )
            logger.info("Device %s install failed, failReason: %s" % (bmc_ip, device_info["failreason"]))
            install_failed_lst.append(bmc_ip)
        else:
            InstallOs.update_os_install_status(
                self.project_id,
                self.pod_id,
                bmc_ip,
                device_info["installstarttime"],
                device_info["installendtime"],
                INSTALL_STATUS_MAPPING_SUC,
                device_info["failreason"]
            )

    def _get_business_ip(self, sub_bmc_info):
        managemant_bond_net = self.net_infos.get("managemant_bond_net")
        managemant_vlan_net = self.net_infos.get("managemant_vlan_net")

        business_ip = list()
        iscsi_plane_slot = sub_bmc_info.get("iscsi_business_plane")
        ip_info = self._config_os_net(sub_bmc_info, managemant_bond_net)
        business_ip.append(ip_info)
        ip_info = self._config_os_net(sub_bmc_info, managemant_vlan_net)
        business_ip.append(ip_info)

        # 非ISCSI场景
        logger.info("----------start-----------")
        if not iscsi_plane_slot:
            self._get_scsi_business_ip(sub_bmc_info, business_ip)
        # ISCSI 场景
        else:
            self._get_iscsi_business_ip(sub_bmc_info, business_ip)
        logger.info("----------end-----------")

        self._get_storage_inner_plane_slot(sub_bmc_info, business_ip)
        self._get_rep_palne_slot(sub_bmc_info, business_ip)
        logger.info("get business ip successful, ip:{}".format(business_ip))
        return business_ip

    def _get_scsi_business_ip(self, sub_bmc_info, business_ip):
        """
        获取非iscsi场景ip_info
        :param args:
        :return:
        """
        management_plane_slot = sub_bmc_info.get("management_plane").split(",")
        storage_plane_slot = sub_bmc_info.get("storage_plane").split(",")
        storage_port_net = self.net_infos.get("storage_port_net")
        storage_vlan_net = self.net_infos.get("storage_vlan_net")
        logger.info("manage plane slot :%s", management_plane_slot)
        logger.info("storage plane slot :%s", storage_plane_slot)
        logger.info("----not iscsi condition----")
        if self.is_same_list(storage_plane_slot, management_plane_slot):
            # 存储不复用管理口，独立配置pvid
            ip_info = self._config_os_net(sub_bmc_info, storage_port_net)
            logger.info("storage is different from management: %s", ip_info)
            business_ip.append(ip_info)
        else:
            # 存储复用管理口，基于管理口bond配置vlan
            ip_info = self._config_os_net(sub_bmc_info, storage_vlan_net)
            logger.info("storage is same as management: %s", ip_info)
            business_ip.append(ip_info)
        return ip_info

    def _get_iscsi_business_ip(self, sub_bmc_info, business_ip):
        """
        获取iscsi场景ip_info
        :param args:
        :return:
        """
        management_plane_slot = sub_bmc_info.get("management_plane").split(",")
        storage_plane_slot = sub_bmc_info.get("storage_plane").split(",")
        iscsi_plane_slot = sub_bmc_info.get("iscsi_business_plane")
        iscsi_independ_bond = self.net_infos.get("iscsi_independ_bond")
        iscsi_reuse_management = self.net_infos.get("iscsi_reuse_management")
        iscsi_reuse_storage = self.net_infos.get("iscsi_reuse_storage")
        iscsi_plane_slot = iscsi_plane_slot.split(",")
        ip_info = self._get_scsi_business_ip(sub_bmc_info, business_ip)
        logger.info("iscsi plane slot :%s", iscsi_plane_slot)
        logger.info("---- iscsi condition----")
        # ISCSI口配置
        # 如果ISCSI复用管理口，基于管理口bond配置vlan
        if not self.is_same_list(iscsi_plane_slot, management_plane_slot):
            logger.info("iscsi is same as management: %s", ip_info)
            ip_info = self._config_os_net(sub_bmc_info, iscsi_reuse_management)
            business_ip.append(ip_info)
        # 如果ISCSI复用存储口，基于存储口bond配置vlan
        elif not list(set(iscsi_plane_slot).difference(set(storage_plane_slot))):
            ip_info = self._config_os_net(sub_bmc_info, iscsi_reuse_storage)
            logger.info("iscsi is same as storage: %s", ip_info)
            business_ip.append(ip_info)
        # 如果ISCSI既不复用管理口，也不复用存储口，则独立组bond
        else:
            ip_info = self._config_os_net(sub_bmc_info, iscsi_independ_bond)
            logger.info("iscsi is different from management and different from storage: %s", ip_info)
            business_ip.append(ip_info)
        logger.info("---- iscsi condition----")

    def _get_storage_inner_plane_slot(self, sub_bmc_info, business_ip):
        """
        :param args:
        :return:
        """
        management_plane_slot = sub_bmc_info.get("management_plane").split(",")
        storage_inner_port_net = self.net_infos.get("storage_inner_port_net")
        storage_inner_vlan_net = self.net_infos.get("storage_inner_vlan_net")
        storage_inner_plane_slot = sub_bmc_info.get("storage_inner_plane")
        if storage_inner_plane_slot:
            storage_inner_plane_slot = storage_inner_plane_slot.split(",")
        if storage_inner_plane_slot:
            if list(set(storage_inner_plane_slot).difference(
                    set(management_plane_slot))):
                # 存储内部口不复用管理口，独立配置pvid
                if storage_inner_port_net:
                    ip_info = self._config_os_net(sub_bmc_info,
                                                  storage_inner_port_net)
                    business_ip.append(ip_info)
            else:
                # 存储后端网络复用管理口，基于管理口bond配置vlan
                if storage_inner_vlan_net:
                    ip_info = self._config_os_net(sub_bmc_info,
                                                  storage_inner_vlan_net)
                    business_ip.append(ip_info)

    def _get_rep_palne_slot(self, sub_bmc_info, business_ip):
        dp_comp = sub_bmc_info.get("deploy_component")
        if not dp_comp or not dp_comp.__contains__("rep"):
            return
        rep_plane_slot = sub_bmc_info.get("replication_plane")
        if rep_plane_slot:
            rep_plane_slot = rep_plane_slot.split(",")
        if rep_plane_slot:
            rep1_bond_net = self.net_infos.get("rep1_bond_net")
            ip_info = self._config_os_net(sub_bmc_info, rep1_bond_net)
            business_ip.append(ip_info)
            rep2_bond_net = self.net_infos.get("rep2_bond_net")
            ip_info = self._config_os_net(sub_bmc_info, rep2_bond_net)
            business_ip.append(ip_info)
            arbitration_net = self.net_infos.get("arbitration_net")
            if arbitration_net:
                ip_info = self._config_os_net(sub_bmc_info, arbitration_net)
                business_ip.append(ip_info)

    def _config_os_net(self, sub_bmc_info, net_info):
        net_plane_list = net_info.get("plane")
        ip_addr = ""
        if "ip_name" in net_info:
            ip_addr = sub_bmc_info.get(net_info.get("ip_name"))
        pci_list = []
        port_list = []
        for net_plane in net_plane_list:
            if "index" in net_info:
                index = int(net_info.get("index"))
                slot_list = sub_bmc_info[net_plane].split(",")[index].split()
                if ip_addr:
                    ip_addr = ip_addr.split(',')[index]
            else:
                slot_list = sub_bmc_info[net_plane].split(",")
            cur_pci_list, cur_port_list = self.get_pci_by_slot(
                sub_bmc_info['bmc_ip'], slot_list)
            pci_list += cur_pci_list
            port_list += cur_port_list
        logger.info('Get pci list.pci_list:%s, port_list: %s' % (
            pci_list, port_list))
        ip_info = self._get_ip_info_for_config_os_net(net_info, ip_addr, pci_list, port_list)
        return ip_info

    def _check_install_os_network(self, bmc_ip_list):
        wait_times = 0
        while True:
            time.sleep(120)
            logger.info("Start to get waiting ping devices status.")
            result = self.odk_api.waitPingDevices(bmc_ip_list)
            logger.info("Get waiting ping devices status over, "
                        "result %s." % result)
            if result['status'] == "false":
                break
            if result['data']:
                wait_times = self._ping_node_list_for_check_os_network(result, wait_times)

    def _ping_node_list_for_check_os_network(self, result, wait_times):
        max_times = 5
        logger.info("Ready devices: %s" % result['data'])
        wait_ping_list = result['data']
        for bmc_ip in wait_ping_list:
            if bmc_ip in self.bmc_info_map:
                node_data = self.bmc_info_map.get(bmc_ip)
                if node_data not in self.wait_ping_node_list:
                    self.wait_ping_node_list.append(node_data)
        # 如安装节点数大于1，要求ping互ping节点至少2个，避免节点自己ping自己一定OK
        wait_bmc_list = [bmc['bmc_ip'] for bmc in self.wait_ping_node_list]
        if len(self.bmc_info_map) > 1 \
                and len(self.wait_ping_node_list) < 2:
            logger.info("Waiting list: %s" % wait_bmc_list)
            wait_times += 1
            if wait_times < max_times:
                return wait_times
        logger.info("Start to ping: %s" % wait_bmc_list)
        success_list, fail_list = self.ping_all_ip_to_end()
        logger.info("Finish to ping.Success list: %s ,"
                    "Fail list: %s " % (success_list, fail_list))
        self.odk_api.updateEndStatus(success_list, fail_list)
        return 0