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

import utils.common.log as logger
from utils.common.ssh_util import Ssh as ssh
from utils.DBAdapter.DBConnector import BaseOps
from utils.common.exception import HCCIException
from utils.business.project_condition_utils import get_project_condition_boolean
from plugins.ResourceCheck.common.libs.BMCCmd import BMCCmdExc
from plugins.DistributedStorage.Deploy.scripts.PreCheck.common.device_operate import PreCheckOperate
from plugins.DistributedStorage.logic.install_operate import InstallOperate


class SPDKDeviceCheck(object):
    def __init__(self, project_id, pod_id):
        self.project_id = project_id
        self.pod_id = pod_id
        self.db = BaseOps()
        self.cpu_support_list = ['Xeon_V4', 'Xeon_V5', 'Jintide', 'Hygon_C86']
        self.nvme_lst = ['19e5', '8086', '144d', '1e81', '1cc4', '1e3b', '1c5f']

    @classmethod
    def get_x86_nodes(cls, bmc_ip_list):
        x86_bmc_ip_list = list()
        cpu_arch_dict = PreCheckOperate.get_system_arch(bmc_ip_list)
        for bmc_ip in bmc_ip_list:
            cpu_arch = cpu_arch_dict.get(bmc_ip).get('stdout')
            if cpu_arch == 'X86':
                x86_bmc_ip_list.append(bmc_ip)
        return x86_bmc_ip_list

    @classmethod
    def get_pool_name_and_nodes_map_dict(cls, all_bmc_data):
        pool_dict = dict()
        for temp in all_bmc_data:
            pool_name = temp.get("storage_pool_name_and_slot")
            if pool_name not in pool_dict.keys():
                pool_dict[pool_name] = list()
                pool_dict.get(pool_name).append(temp)
            else:
                pool_dict.get(pool_name).append(temp)
        return pool_dict

    def procedure(self):
        all_bmc_data = self.db.get_install_os_list_info(self.pod_id)
        if get_project_condition_boolean(self.project_id, '!TenantStorFB_Heterogeneous'):
            self.check_spdk_when_install_os_with_tools(all_bmc_data)
        else:
            self.check_spdk_when_install_os_without_tools(all_bmc_data)

    def check_spdk_when_install_os_with_tools(self, all_bmc_data):
        bmc_client = BMCCmdExc()
        pool_dict = self.get_pool_name_and_nodes_map_dict(all_bmc_data)
        nvme_node_list = self.get_nvme_node_list(bmc_client, pool_dict)
        if nvme_node_list:
            logger.info("The cache type is NVME, need to check SPDK")
            x86_bmc_ip_list = self.get_x86_nodes(nvme_node_list)
            if x86_bmc_ip_list:
                self.check_cpu_type_when_install_os_with_tools(bmc_client, x86_bmc_ip_list)

    def check_cpu_type_when_install_os_with_tools(self, bmc_client, x86_bmc_ip_list):
        # x86架构的节点检查cpu type是否为[Xeon_V4、Xeon_V5、Jintide、Hygon C86]
        # Hygon C86海光服务器不检查SPDK，所以加进白名单
        # Jintide包含C4、C5、C6
        logger.info("Checking cpu type")
        cpu_result = bmc_client.run(x86_bmc_ip_list, X86_CPU_TYPE)
        for bmc_ip in x86_bmc_ip_list:
            if cpu_result[bmc_ip]['result'] != '0':
                stderr = cpu_result[bmc_ip]['stderr']
                logger.error("Failed to get CPU type from node[%s], DetaiL:%s" % (bmc_ip, stderr))
                continue
            cpu_type_list = cpu_result[bmc_ip]['stdout'].strip('\n').split('\n')
            logger.info("Current node[%s] cpu type list:%s" % (bmc_ip, cpu_type_list))
            for cpu in cpu_type_list:
                if cpu not in self.cpu_support_list:
                    logger.error("The CPU type not supported")
                    raise HCCIException(627605, bmc_ip)

    def get_nvme_node_list(self, bmc_client, pool_dict):
        nvme_node_list = list()
        cmd = "lspci -mm -n -D | grep 0108 | tr -d '\"'| awk '{print $3}'"
        for key, data in pool_dict.items():
            logger.info("start to check pool,pool name [%s]", key)
            bmc_cache = data[0].get('cache_type')
            if not (bmc_cache == 'ssd_card' or bmc_cache == "none"):
                continue
            bmc_ip_list = [bmc.get('bmc_ip') for bmc in data]
            nvme_result = bmc_client.run(bmc_ip_list, cmd)
            for bmc_ip in bmc_ip_list:
                if nvme_result.get(bmc_ip).get('result') != '0':
                    stderr = nvme_result.get(bmc_ip).get('stderr')
                    logger.error("Failed to get nvme type from node[%s], DetaiL:%s" % (bmc_ip, stderr))
                    continue
                if nvme_result.get(bmc_ip).get('stdout') == "":
                    logger.info("The host[%s] cache type is not NVME,no need to check SPDK" % bmc_ip)
                    continue
                self.check_node_nvme_disk_when_install_os_with_tools(bmc_ip, nvme_node_list, nvme_result)
        return nvme_node_list

    def check_node_nvme_disk_when_install_os_with_tools(self, bmc_ip, nvme_node_list, nvme_result):
        # 检查NVMe SSD缓存厂商是否[es3000，intel，samsung，A28, DP]
        logger.info("Checking nvme type")
        nvme_disk_list = nvme_result.get(bmc_ip).get('stdout').strip('\n').split('\n')
        logger.info("Current node[%s] nvme:%s" % (bmc_ip, nvme_disk_list))
        nvme_node_list.append(bmc_ip)
        for nvme in nvme_disk_list:
            if nvme not in self.nvme_lst:
                logger.error("The nvme disk[%s] is not huawei or intel or samsung or white-lable nvme disk." % nvme)
                raise HCCIException(627436, bmc_ip)

    def check_spdk_when_install_os_without_tools(self, all_bmc_data):
        # 手动装机场景
        operate = InstallOperate()
        nvme_cmd = "lspci -mm -n -D | grep 0108 | tr -d '\"'| awk '{print $3}'"
        for node in all_bmc_data:
            om_ip = node.get("manageIp")
            if not (node.get('cache_type') == 'ssd_card' or node.get('cache_type') == "none"):
                logger.info("The host[%s] cache type is not NVME, no need to check SPDK" % om_ip)
                continue
            account_info = node["creuser"].split(',')
            user = account_info[2]
            passwd = account_info[3]
            root_pwd = account_info[1]
            ssh_client = operate.create_ssh_root_client(om_ip, user, passwd, root_pwd)
            ret_cmd = ssh.ssh_exec_command_return(ssh_client, nvme_cmd)
            if not ret_cmd:
                logger.info("The host[%s] cache type is not NVME, no need to check SPDK" % om_ip)
                continue
            self.check_nvme_when_install_os_without_tools(om_ip, ret_cmd)
            cpu_arch = operate.get_cpu_arch(ssh_client)
            if cpu_arch == 'x86_64':
                self.check_cpu_type_when_install_os_without_tools(om_ip, ssh_client)

    def check_cpu_type_when_install_os_without_tools(self, om_ip, ssh_client):
        # x86架构的节点检查cpu type是否为[Xeon_V4、Xeon_V5、Jintide、Hygon C86]
        # Hygon C86海光服务器不检查SPDK，所以加进白名单
        # Jintide包含C4、C5、C6
        logger.info("Checking cpu type")
        ret_cmd = ssh.ssh_exec_command_return(ssh_client, X86_CPU_TYPE)
        logger.info("The x86_cpu_type query result : %s", str(ret_cmd))
        index = -2
        for content in ret_cmd:
            if re.findall('sh /x86_cpu_type.sh', content):
                index = ret_cmd.index(content)
                break
        cpu_type_list = ret_cmd[index + 1:]
        logger.info("Current node[%s] cpu type list:%s" % (om_ip, cpu_type_list))
        for cpu in cpu_type_list:
            if cpu.strip('\n') not in self.cpu_support_list:
                logger.error("The CPU type not supported")
                raise HCCIException(627605, om_ip)

    def check_nvme_when_install_os_without_tools(self, om_ip, ret_cmd):
        # 检查NVMe SSD缓存厂商是否[es3000，intel，samsung，A28]
        logger.info("Checking nvme type")
        for nvme in ret_cmd:
            if nvme.strip('\n') not in self.nvme_lst:
                logger.error("The nvme disk[%s] is not huawei or intel or samsung or white-lable nvme disk." % nvme)
                raise HCCIException(627436, om_ip)


X86_CPU_TYPE = r"""
cat << EOF >/x86_cpu_type.sh
#!/bin/bash

# Hygon C86 不支持spdk,直接返回
cat /proc/cpuinfo|grep 'model name'|sort -k 3,6 -u|grep -q 'Hygon C86'
if [ \$? -eq 0 ]
then
    echo "Hygon_C86"
    exit 0
fi

#Xeon V4以上才能使用spdk
cat /proc/cpuinfo | grep 'model name' | sort -k 4,9 -u | grep -iq -e 'Xeon' -e 'Jintide'
if [ \$? -ne 0  ];then
    echo "Other"
    exit 0
fi

#C4、C5、C6
cat /proc/cpuinfo | grep 'model name' |sort -k 4,9 -u | awk -F':' '{print \$2}' | awk '{ for(i =1; i<=NF; i++) {print \$i}  }' | grep -qi -e C4215R -e C5218R -e C5220R -e C6230R -e C6330
if [  \$? -eq 0 ];then
    echo "Jintide"
    exit 0
fi

#V5
cat /proc/cpuinfo | grep 'model name' |sort -k 4,9 -u | awk -F':' '{print \$2}' | awk '{ for(i =1; i<=NF; i++) {print \$i}  }' | grep -qi -e Platinum -e Gold -e Silver -e Bronze
if [ \$? -eq 0 ];then
    echo "Xeon_V5"
fi

#V4
xeonCpuV4Verion=\$(cat /proc/cpuinfo | grep 'model name' |sort -k 4,9 -u | awk -F':' '{print \$2}' | awk '{ for(i =1; i<=NF; i++) {print \$i}  }' | grep -i -e "v[0-9]" | awk -F'v' '{print \$2}' | awk '{temp=\$1} END{print temp}')
if [ x"\${xeonCpuV4Verion}" == x"4" ];then
    echo "Xeon_V4"
fi

exit 0
EOF
sh /x86_cpu_type.sh """
