# -*- coding: utf-8 -*-
from plugins.ResourceCheck.common.libs import common_libs
from plugins.ResourceCheck.common.libs import raid_libs
from utils.common.fic_base import StepBaseInterface
from utils.common.message import Message
from utils.DBAdapter.DBConnector import BaseOps
import utils.common.log as logger
import time
import os
from utils.common.exception import HCCIException


class Do_Check_Slots():
    def __init__(self, project_id, pod_id):
        self.this_path = os.path.realpath(__file__ + '/../../')
        self.script_dst_dir = "/home/pkg/precheck/scripts/"
        self.db = BaseOps()
        self.project_id = project_id
        self.pod_id = pod_id
        self.cascaded_pod_id = int(pod_id) + 1

    def procedure(self):

        """
        检查管理节点、云服务节点的CPU
       """
        try:
            common_libs.check_flag()
            common_libs.purge_http_log()
            checktype = 'disk_info'
            timestamp = str(int(time.time()))
            bmc_ip_list_zk = []
            bmc_ip_list_prm = []
            error_list = []
            nodes_info_dic = {}
            primary_slot_total = 0
            zk_slot_total = 0
            nodes = self.db.get_bmc_info_by_pod_id(self.pod_id) \
                    + self.db.get_bmc_info_by_pod_id(self.cascaded_pod_id)
            nodes_info = [node for node in nodes if
                          node["bmc_role"] in ['kvm', 'dpdk']]
            for node in nodes_info:
                bmc_ip = node["bmc_ip"]
                zk_slot = node["zk_slot"]
                primary_slot = node["primary_slot"]
                nodes_info_dic[bmc_ip] = {}
                if zk_slot:
                    zk_slot_total = zk_slot_total + 1
                    nodes_info_dic[bmc_ip]['zk_slot'] = zk_slot
                    bmc_ip_list_zk.append(bmc_ip)
                else:
                    return True
                if primary_slot:
                    primary_slot_start, primary_slot_end = primary_slot.split('-')
                    primary_slot_total = primary_slot_total + int(primary_slot_end) - int(primary_slot_start) + 1
                    nodes_info_dic[bmc_ip]['prm_slot_start'] = primary_slot_start
                    nodes_info_dic[bmc_ip]['prm_slot_end'] = primary_slot_end
                    bmc_ip_list_prm.append(bmc_ip)

            if not bmc_ip_list_zk:
                logger.error('All hosts have no zk disk, please check LLD sheet device_information')
                raise HCCIException('113084')

            if not bmc_ip_list_prm:
                logger.error('All hosts have no primary storage disk, please check LLD sheet device_information')
                raise HCCIException('113085')

            if zk_slot_total < 3:
                logger.error('Number of MDC must be greater than 3, but only %d' % zk_slot_total)
                raise HCCIException('113086', zk_slot_total)

            if primary_slot_total < 12:
                logger.error('Number of primary disks must be greater than 12, but only %d' % primary_slot_total)
                raise HCCIException('113087', primary_slot_total)

            # 从主机直接获取所有节点RAID卡型号、ID
            bmc_ip_list = list(set(bmc_ip_list_zk + bmc_ip_list_prm))
            host_raid_obj = raid_libs.HostRAIDCls(self.project_id, bmc_ip_list)

            # 从raid_lib获取支持的RAID卡型号、ID、raid_check_lib
            supported_bmc_ip_list = []
            for bmc_ip in bmc_ip_list:
                logger.info('Checking RAID compatibility for node: %s' % bmc_ip)
                host_supported_ctl_info = host_raid_obj.check_disk_controller_model(bmc_ip)
                if not host_supported_ctl_info:
                    host_raid_dev_list = host_raid_obj.get_host_raid_dev_info(bmc_ip)
                    logger.error('RAID controller on node: %s is not supported. Model: %s' %
                                 (bmc_ip, host_raid_dev_list))
                    error_list.append(('113061', host_raid_dev_list, bmc_ip))
                else:
                    logger.info('Create checking script for node: %s' % bmc_ip)
                    raid_libs.CheckRAID(self.project_id, bmc_ip, checktype, timestamp).create_check_script()
                    supported_bmc_ip_list.append(bmc_ip)

            common_libs.check_all_result(bmc_ip_list, checktype, timestamp)

            for bmc_ip in supported_bmc_ip_list:
                logger.info('Checking node: %s' % bmc_ip)
                zk_slot = nodes_info_dic[bmc_ip].get('zk_slot')
                prm_slot_start = int(nodes_info_dic[bmc_ip]['prm_slot_start'])
                prm_slot_end = int(nodes_info_dic[bmc_ip]['prm_slot_end'])
                raid_obj = raid_libs.CheckRAID(self.project_id, bmc_ip, checktype, timestamp)
                raid_obj.get_disk_info_all()
                # check slot
                logger.info('Checking zk and primary disk slots')
                slot_list = list(range(prm_slot_start, prm_slot_end))
                slot_error = []
                slot_raid = []
                slot_empty = []
                if zk_slot:
                    zk_slot = int(zk_slot)
                    slot_list = slot_list + [zk_slot]
                for slot in slot_list:
                    if raid_obj.check_disk_exist(slot):
                        logger.info('BMC: %s, slot %s has a disk.' % (bmc_ip, slot))
                        logger.info('Checking error of BMC: %s, slot %s.' % (bmc_ip, slot))
                        ret, msg = raid_obj.check_disk_has_error(slot=slot)
                        if ret:
                            msg = 'slot %s has error, msg: %s.' % (slot, msg)
                            logger.error(msg)
                            slot_error.append(slot)

                        logger.info('Checking if BMC: %s slot %s is a member of RAID' % (bmc_ip, slot))
                        ret = raid_obj.check_disk_in_raid(slot=slot)
                        if ret:
                            msg = 'slot %s has been added to a raid.' % slot
                            logger.error(msg)
                            slot_raid.append(slot)
                    else:
                        msg = 'BMC: %s, slot %s has no disk.' % (bmc_ip, slot)
                        logger.error(msg)
                        slot_empty.append(slot)
                if slot_empty:
                    error_list.append(('113081', str(slot_empty), bmc_ip))
                if slot_error:
                    error_list.append(('113083', str(slot_error), bmc_ip))
                if slot_raid:
                    error_list.append(('113088', str(slot_raid), bmc_ip))

            if error_list:
                common_libs.report_all_error(error_list)
            else:
                return True
        except HCCIException as e:
            raise e
        except Exception as e:
            logger.error("Error msg:%s" % str(e))
            raise HCCIException('113999', str(e))

        return True


class CheckSlots(StepBaseInterface):
    def __init__(self, project_id, pod_id):
        super(CheckSlots, self).__init__(project_id, pod_id)
        self.project_id = project_id
        self.pod_id = pod_id
        self.implement = Do_Check_Slots(self.project_id, self.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:
            ret_code = self.implement.procedure()
            if ret_code == True:
                return Message(200)
        except HCCIException as e:
            return Message(500, e)

    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
