# -*- coding: utf-8 -*-
import utils.common.log as logger
from plugins.DistributedStorage.Deploy.scripts.PreCheck.common.DeviceOperate import CpuOperate
from plugins.ResourceCheck.common.libs.BMCCmd import BMCCmdExc
from utils.business.hardware_driver_util import DriverApi
from utils.DBAdapter.DBConnector import BaseOps
from utils.common.exception import HCCIException
from utils.common.fic_base import StepBaseInterface
from utils.common.fic_base import TestCase
from utils.common.message import Message


class DoCheckDisk(TestCase):
    def __init__(self, project_id, pod_id):
        super(DoCheckDisk, self).__init__(project_id, pod_id)
        self.project_id = project_id
        self.pod_id = pod_id

    def pre_condition(self):
        pass

    def procedure(self):

        """
        检查eBackupDISK
       """
        try:
            # 查询带装机的IP
            self.cmd_exe = BMCCmdExc()
            self.db = BaseOps()
            self.bmc_info_lists = self.db.get_install_os_list_info(self.pod_id)
            # 判断是否为全消A场景,全消A场景与非全消A场景查询硬盘容量执行不同命令
            x86_full_off_ip_list, arm_full_off_ip_list, other_ip_list = self.divide_ip_list()
            if x86_full_off_ip_list:
                self.check_disk_capacity(x86_full_off_ip_list, FULL_OFF_CMD_FOR_X86)
            if arm_full_off_ip_list:
                self.check_disk_capacity(arm_full_off_ip_list, FULL_OFF_CMD_FOR_ARM)
            if other_ip_list:
                cmd = "fdisk -l | grep 'Disk /dev/sd' | head -n 1 | awk '{print int($5/1024/1024/1024)}'"
                self.check_disk_capacity(other_ip_list, cmd)
            return True, None
        except HCCIException as e1:
            raise e1
        except Exception as e2:
            raise e2

    def divide_ip_list(self):
        """
        根据节点是否为full_off_A划分不同节点
        :param project_id:
        :param pod_id:
        :return:full_off_A节点IP列表和非full_off_A节点（Raid与half_off_A）列表
        """
        full_off_ip_list = []
        other_ip_list = []
        for sub_bmc_info in self.bmc_info_lists:
            bmc_ip = sub_bmc_info.get("bmc_ip")
            if CpuOperate.get_1880_raid_node([bmc_ip]).get(bmc_ip).get('is_1880'):
                logger.info("This [{}] is 1880 Raid card, pass".format(bmc_ip))
                continue
            if CpuOperate.get_3152_raid_node([bmc_ip]).get(bmc_ip).get('is_3152'):
                logger.info("[{}] This is 3152 Raid card, pass".format(bmc_ip))
                continue
            raid_card_flag = DriverApi().check_host_is_hard_raid(bmc_ip)
            if not raid_card_flag:
                full_off_ip_list.append(bmc_ip)
                msg = ("There is no RAID card on the server [%s],"
                       "full off A mode" % bmc_ip)
                logger.info(msg)
            else:
                other_ip_list.append(bmc_ip)
        x86_ip_list, arm_ip_list = self.cpu_classification(full_off_ip_list)
        logger.info("Full off A bmc ip list X86: %s ARM: %s, other bmc ip list:%s" %
                    (x86_ip_list, arm_ip_list, other_ip_list))
        return x86_ip_list, arm_ip_list, other_ip_list

    def check_disk_capacity(self, bmc_ip_list, cmd):
        disk_min_required = 400
        disk_max_required = 2048
        result = self.cmd_exe.run(bmc_ip_list, cmd)
        logger.info("Exec result: %s" % result)
        for bmc_info in self.bmc_info_lists:
            bmc_ip = bmc_info["bmc_ip"]
            if not result.get(bmc_ip):
                continue
            logger.info("bmc_ip:%s Disk check" % bmc_ip)
            bmc_result = result[bmc_ip]
            if bmc_result["result"] == '0':
                discs = bmc_result["stdout"]
                if not discs:
                    err_msg = "The first disk does not exist."
                    logger.error(err_msg)
                    raise Exception(err_msg)
                disk_size_list = discs.strip().split(" ")
                for disk_size in disk_size_list:
                    logger.info("Disk_size is %s" % disk_size)
                    if int(disk_size) >= disk_min_required and int(disk_size) <= disk_max_required:
                        logger.info("Disk_size check is ok !")
                    else:
                        logger.error("Disk_size check is Failed! BMC: %s,"
                                     " Current Configuration: %s GB, Required Configuration: %s ~ %s GB." %
                                     (bmc_ip, disk_size,
                                      disk_min_required, disk_max_required))

                        raise HCCIException("625306", bmc_info["equipment_model"],
                                           bmc_ip, disk_size,
                                           disk_min_required, disk_max_required
                                           )

            else:
                logger.info("Disk_size check is Failed,%s!", bmc_result["stderr"])
                raise HCCIException("625301", bmc_result["stderr"])

    def cpu_classification(self, bmc_ip_list):
        """
        根据cpu类型就行分组处理，x86和arm服务器软raid检查系统盘方法不同
        :param bmc_ip_list:
        :return: list
        """
        logger.info("Checking cpu type")
        operate = CpuOperate()
        cpu_arch_dict = operate.get_system_arch(bmc_ip_list)
        x86_ip_list, arm_ip_list = list(), list()
        for _ip, value in cpu_arch_dict.items():
            if value.get("stdout") == "X86":
                x86_ip_list.append(_ip)
            if value.get("stdout") == "ARM":
                arm_ip_list.append(_ip)
        return x86_ip_list, arm_ip_list

    def post_condition(self):
        pass

    def failure(self):
        super(DoCheckDisk, self).failure()
        # 环境恢复脚本


class CheckDisk(StepBaseInterface):
    def __init__(self, project_id, pod_id):
        super(CheckDisk, self).__init__(project_id, pod_id)
        self.project_id = project_id
        self.pod_id = pod_id
        self.implement = DoCheckDisk(project_id, pod_id)

    def pre_check(self, project_id, pod_id):
        """
        插件内部接口：执行安装前的资源预检查，该接口由execute接口调用，工具框架不会直接调用此接口。
        :param project_id:
        :param pod_id:
        :return:
        """
        pass

    def execute(self, project_id, pod_id):
        try:
            self.implement.procedure()
            return Message(200)
        except HCCIException as e1:
            return Message(500, e1)
        except Exception as e2:
            return Message(500, HCCIException('625301', str(e2)))

    def rollback(self, project_id, pod_id):
        """
        标准调用接口：执行回滚
        :param project_id:
        :param pod_id:
        :return:Message类对象
        """
        return Message(200)

    def retry(self, project_id, pod_id):
        """
        标准调用接口：重试
        :return: Message类对象
        """
        return self.execute(project_id, pod_id)

    def check(self, project_id, pod_id):
        """
        标准调用接口：重试
        :param project_id:
        :param pod_id:
        :return:
        """
        pass


# ARM服务器全消A场景查询系统盘命令
FULL_OFF_CMD_FOR_ARM = r'''
rear_slot1=4
rear_slot2=5
#System disk plugged on the I/O module 1 rear plate system disk
fs_sd1=$(ls /sys/devices/pci0000\:74/0000\:74\:04.0/host*/phy-*\:${rear_slot1}/port*/end_device-*/target*/*/block/ 2>/dev/null)
fs_sd2=$(ls /sys/devices/pci0000\:74/0000\:74\:04.0/host*/phy-*\:${rear_slot2}/port*/end_device-*/target*/*/block/ 2>/dev/null)

#Match slot failed, using rear panel no.4 and no.5 slot to create raid by default
if [ -z "${fs_sd1}" -o -z "${fs_sd2}" ]; then
    fs_sd1=$(ls /sys/devices/pci0000\:b4/0000\:b4\:04.0/host*/phy-*\:${rear_slot1}/port*/end_device-*/target*/*/block/ 2>/dev/null)
    fs_sd2=$(ls /sys/devices/pci0000\:b4/0000\:b4\:04.0/host*/phy-*\:${rear_slot2}/port*/end_device-*/target*/*/block/ 2>/dev/null)
fi

front_slot1=0
front_slot2=1
#Match slot failed, using front panel no.0 and no.1 slot to create raid by default
if [ -z "${fs_sd1}" -o -z "${fs_sd2}" ]; then
    fs_sd1=$(ls /sys/devices/pci0000\:74/0000\:74\:02.0/host*/phy-*\:${front_slot1}/port*/end_device-*/target*/*/block/ 2>/dev/null)
    fs_sd2=$(ls /sys/devices/pci0000\:74/0000\:74\:02.0/host*/phy-*\:${front_slot2}/port*/end_device-*/target*/*/block/ 2>/dev/null)
fi

#Match slot failed, using CPU2 front panel no.0 and no.1 slot to create raid by default
if [ -z "${fs_sd1}" -o -z "${fs_sd2}" ]; then
    fs_sd1=$(ls /sys/devices/pci0000\:b4/0000\:b4\:02.0/host*/phy-*\:${front_slot1}/port*/end_device-*/target*/*/block/ 2>/dev/null)
    fs_sd2=$(ls /sys/devices/pci0000\:b4/0000\:b4\:02.0/host*/phy-*\:${front_slot2}/port*/end_device-*/target*/*/block/ 2>/dev/null)
fi
disk_size1=$(fdisk -l | grep 'Disk /dev/'${fs_sd1} | head -n 1 | awk '{print int($5/1024/1024/1024)}')
disk_size2=$(fdisk -l | grep 'Disk /dev/'${fs_sd2} | head -n 1 | awk '{print int($5/1024/1024/1024)}')
echo ${disk_size1} ${disk_size2}
'''
# X86服务器全消A场景查询系统盘命令
FULL_OFF_CMD_FOR_X86 = r"""
function get_same_capacity_index() {
    local sizeArray=("${@:3}")
    sizeNum=${#sizeArray[@]}
    for((i=0;i<$sizeNum;i++))
    do
       for((j=$i+1;j<$sizeNum;j++))
       do
           if [ ${sizeArray[$i]} -eq ${sizeArray[$j]}  ];then
             eval $1=$i
             eval $2=$j
             return
           fi
       done
    done
}
function get_driver()
{
    devNum=0
    # 组软raid的卡容量大于400
    raid_size=400
    cd /sys/devices/pci0000\:00
    target=`find -name 'target*' -type d | grep ata`
    targetN=($target)
    devNum=${#targetN[@]}
    if [ $devNum -gt 4 ] || [ $devNum -lt 2 ]; then
        return
    fi
    sdArray=()
    sizeArray=()
    for tar in ${targetN[@]}
    do
        cd /sys/devices/pci0000\:00/$tar
        block=`find -name 'block' -type d`
        cd $block
        sd=`ls`
        sd_size=`lsblk | grep $sd | awk 'NR==1 {print $4}' | awk -F '.' '{print int($1)}'`
        if [[ $sd_size -gt $raid_size ]]; then
            sdArray=(${sdArray[@]} $sd)
            sizeArray=(${sizeArray[@]} $sd_size)
        fi
    done
    eval get_same_capacity_index key1 key2 "${sizeArray[@]}"
    eval $1=${sdArray[$key1]}
    eval $2=${sdArray[$key2]}
}
function check_v6_12nvme()
{
    # 检测riser卡单板id 轮询1-3 倒数第四位
    riser_id=()
    for((i=1;i<=3;i++))
    do
        slot_id=$(printf '%#X' $i)
        borad_id=`ipmitool raw 0x30 0x93 0xDB 0x07 0x00 0x27 0x0f $slot_id 0x06 0x00 0x02 | awk '{print $5}'`
        if [ x"$borad_id" = x"" ]; then
            return 1
        fi

        if [ $borad_id = "30" ]; then
            riser_id=(${riser_id[@]} $borad_id)
        fi
        if [ ${#riser_id[@]} -eq 2 ]; then
            break
        fi
    done
    if [ ${#riser_id[@]} -ne 2 ]; then
        return 1
    fi

    # 检测硬件背板单板id 轮询1-10 倒数第四位
    back_id=()
    for((i=1;i<=10;i++))
    do
        slot_id=$(printf '%#X' $i)
        borad_id=`ipmitool raw 0x30 0x93 0xDB 0x07 0x00 0x27 0x05 $slot_id 0x06 0x00 0x02 | awk '{print $5}'`
        if [ x"$borad_id" = x"" ]; then
            return 1
        fi

        if [ $borad_id = "88" ] || [ $borad_id = "4b" ]; then
            back_id=(${back_id[@]} $borad_id)
        fi
        if [ ${#back_id[@]} -eq 2 ]; then
            return 0
        fi
    done
    return 1
}
check_v6_12nvme
v6_12nv_flag=$?
if [ $v6_12nv_flag -eq 0 ]; then
    eval get_driver fs_sd1 fs_sd2
fi
#匹配后面板槽位失败，默认使用前面板0号与1号槽位创建raid（IO模组2）
if [ -z "${fs_sd1}" -o -z "${fs_sd2}" ]; then
    exit 1
fi
disk_size1=$(fdisk -l | grep 'Disk /dev/'${fs_sd1} | head -n 1 | awk '{print int($5/1024/1024/1024)}')
disk_size2=$(fdisk -l | grep 'Disk /dev/'${fs_sd2} | head -n 1 | awk '{print int($5/1024/1024/1024)}')
echo ${disk_size1} ${disk_size2}
"""
