# -*- 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.OpenStackNodeManager import OpenStackNodeManager
from utils.common.message import Message
from utils.DBAdapter.DBConnector import BaseOps
import utils.common.log as logger
import time
import os
import traceback
from utils.common.exception import HCCIException


class DoCheckSlots:
    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

    def procedure(self):
        """
            检查云服务节点的RAID卡型号是否支持、主存槽位是否有盘
       """
        try:
            common_libs.check_flag()
            common_libs.purge_http_log()
            check_type = 'disk_info'
            timestamp = str(int(time.time()))
            bmc_ip_list_prm = []
            error_list = []
            nodes_info_dic = {}
            nodes_info = OpenStackNodeManager.get_manage_az_nodes_info(self.db, self.pod_id)
            nodes_info = [node for node in nodes_info if 'osd' in node.get('ref_component')]
            if not nodes_info:
                logger.info('no osd node need to check')
                return True
            for node in nodes_info:
                bmc_ip = node["bmc_ip"]
                primary_slot = node["primary_slot"]
                nodes_info_dic[bmc_ip] = {}
                if primary_slot:
                    primary_slot_start, primary_slot_end = primary_slot.split('-')
                    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
                    if primary_slot_total < 4:
                        err_msg = "the number of main storage disks Less than 4 in the LLD"
                        logger.error(err_msg)
                        raise Exception(err_msg)
                    bmc_ip_list_prm.append(bmc_ip)
            if not bmc_ip_list_prm:
                logger.error('All hosts have no primary storage disk, please check LLD sheet device_information')
                raise HCCIException(113085)

            # 从主机直接获取所有节点RAID卡型号、ID
            bmc_ip_list = 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, check_type, timestamp).create_check_script()
                    supported_bmc_ip_list.append(bmc_ip)

            common_libs.check_all_result(supported_bmc_ip_list, check_type, timestamp)

            for bmc_ip in supported_bmc_ip_list:
                logger.info('Checking node: %s' % bmc_ip)
                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, check_type, timestamp)
                raid_obj.get_disk_info_all()
                logger.info('Checking primary disk slots')
                slot_list = list(range(prm_slot_start, prm_slot_end + 1))
                slot_error = []
                slot_raid = []
                slot_empty = []
                total_slots = 0
                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)
                        total_slots += 1
                    else:
                        msg = 'BMC: %s, slot %s has no disk.' % (bmc_ip, slot)
                        logger.error(msg)
                        slot_empty.append(slot)
                if total_slots < 4:
                    err_msg = "The number of physical disks on the current node [%s] is %s, which is less than 4." % (bmc_ip, total_slots)
                    logger.error(err_msg)
                    raise Exception(err_msg)

                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))
            logger.error(traceback.format_exc())
            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 = DoCheckSlots(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:
                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
