# -*-coding:utf-8-*-
import re
import ipaddress

import utils.common.log as logger
from utils.business.project_util import ProjectApi
from utils.common.param_check import check_param_ip
from utils.common.error.fcd_error_code import get_code_msg
from platforms.project.ProjectUtils import get_project_conditions
from platforms.project.ProjectUtils import get_project_condition_boolean
from plugins.DistributedStorage.params.network_utils import get_subnet
from plugins.DistributedStorage.params.network_utils import is_ip_in_net
from plugins.DistributedStorage.params.network_utils import is_ip_net_ip
from plugins.DistributedStorage.params.network_utils import is_ip_broadcast_ip
from plugins.DistributedStorage.params.network_utils import is_ip_in_section
from plugins.DistributedStorage.params.network_utils import does_net_match_mask
from plugins.DistributedStorage.params.network_utils import START_ADDR_MSG
from plugins.DistributedStorage.params.network_utils import START_ADDR_ERROR_MSG
from plugins.DistributedStorage.params.network_utils import END_ADDR_MSG
from plugins.DistributedStorage.params.network_utils import END_ADDR_ERROR_MSG
from plugins.DistributedStorage.params.network_utils import IP_POOL_ERROR_MSG
from plugins.DistributedStorage.params.network_utils import GW_ERROR_NOCONTAIN
from plugins.DistributedStorage.params.network_utils import GW_NET_ERROR_MSG
from plugins.DistributedStorage.params.network_utils import GW_BROADCAST_ERROR_MSG
from plugins.DistributedStorage.params.network_utils import GW_ERROR_CONTAIN
from plugins.DistributedStorage.params.network_utils import SUBNET_MASK_ERROR_MSG
from plugins.DistributedStorage.scripts.utils.common.DeployConstant import DeployConstant


class BaseParamCheckHook(object):
    def __init__(self, exist_list, ip_list, reachable_list):
        self.exist_list = exist_list
        self.ip_list = ip_list
        self.reachable_list = reachable_list

    def check(self, input_params, project_id):
        if not input_params:
            return True, ''
        temp_params = self.resolve_input_params(input_params)
        error_msg_dict = self.check_params(temp_params, project_id, self.exist_list, self.ip_list)
        if not error_msg_dict:
            logger.info('check param ok.')
            return True, ''
        return False, error_msg_dict

    def check_params(self, input_params, project_id, exist_list, ip_list):
        """
        检查参数是否填写、IP是否与工程选择的IPV4或IPV6、掩码和vlan是否合规
        input_params: [{"key": "bmc_ip", "value: "xxx.xxx.xxx.xxx"},
                       {"key":"bmc_passwd", "value": "******"}...]
        """
        error_msg_dict = {}
        # 将input_params转换成dict
        if ProjectApi().is_ipv6_project(project_id):
            ip_version = 6
        else:
            ip_version = 4
        for param_item in input_params:
            if param_item['key'] not in exist_list:
                continue
            # 非空flag
            no_empty_flag = True
            if param_item['key'] == "hostname":
                MATCH_RE = '^(?!-|\.)[A-Za-z0-9-\.]{1,64}(?!-|\.)$'
                if re.match(MATCH_RE, param_item['value']) is None:
                    error_msg_dict[param_item['key']] = get_code_msg('626272') % param_item['key']
            # check not empty
            if not param_item['value']:
                no_empty_flag = False
                error_msg_dict[param_item['key']] = get_code_msg('626260') % param_item['key']
            # check is ip
            if no_empty_flag and param_item['key'] in ip_list:
                if not check_param_ip(param_item['value'], ip_version=ip_version):
                    error_msg_dict[param_item['key']] = \
                        get_code_msg('626261') % (param_item['key'], param_item['value'])
            # 基本参数检查：检查掩码、vlan
            error_dict = self.check_network_params(param_item, ip_version, no_empty_flag)
            error_msg_dict.update(error_dict)

        error_dict = self.check_network_ip_range(input_params, error_msg_dict)
        error_msg_dict.update(error_dict)
        return error_msg_dict

    def resolve_input_params(self, input_params):
        return input_params

    def check_network_params(self, param_item, ip_version, no_empty_flag):
        return {}

    def check_network_ip_range(self, input_params, error_msg_dict):
        return {}


class InstallOSServerListCheckHook(BaseParamCheckHook):
    """
    华为分布式存储分离部署参数检查
    """
    def resolve_input_params(self, input_params):
        """
        return: [{"key": "bmc_ip", "value: "xxx.xxx.xxx.xxx"}, ...]
        """
        return [{'key': key, "value": value} for key, value in input_params.items()]


class InstallOSParamCheckHook(BaseParamCheckHook):
    """
    基本参数检查
    """
    def __init__(self, exist_list, ip_list, reachable_list, ip_format_list):
        super(InstallOSParamCheckHook, self).__init__(exist_list, ip_list, reachable_list)
        self.ip_format_list = ip_format_list
        self.params = {}

    def check_network_params(self, param_item, ip_version, not_empty_flag):
        error_dict = {}
        # check mask
        mask_error_dict = self.check_network_mask_params(param_item, ip_version, not_empty_flag)
        error_dict.update(mask_error_dict)
        # check vlan
        if not_empty_flag is True and param_item['key'] in self.ip_format_list and "_vlan" in param_item['key']:
            if str(param_item['value']).isdigit():
                if int(param_item['value']) < 0 or int(param_item['value']) > 4096:
                    error_dict[param_item['key']] = get_code_msg('626256') % (param_item['key'], param_item['value'])
            else:
                error_dict[param_item['key']] = get_code_msg('626256') % (param_item['key'], param_item['value'])
        return error_dict

    def check_network_mask_params(self, param_item, ip_version, not_empty_flag):
        error_dict = dict()
        if not_empty_flag is True and param_item['key'] in self.ip_format_list \
                and "_netmask" in param_item['key']:
            if ip_version == 4:
                MASK_RE = '^(254|252|248|240|224|192|128|0)\.0\.0\.0|255\.(254|252|248|240|224|192|128|0)' \
                          '\.0\.0|255\.255\.(254|252|248|240|224|192|128|0)\.0|255\.255\.255\.(254|252|248|' \
                          '240|224|192|128|0)$'
                if re.match(MASK_RE, str(param_item['value'])) is None:
                    error_dict[param_item['key']] = get_code_msg('626254') % (param_item['key'], param_item['value'])
            if ip_version == 6:
                if not str(param_item['value']).isdigit() or \
                        str(param_item['value']).isdigit() and \
                        int(param_item['value']) < 32 or int(param_item['value']) > 126:
                    error_dict[param_item['key']] = get_code_msg('626255') % \
                                                    (param_item['key'], param_item['value'])
        return error_dict

    def get_network_set(self):
        network_set = set()
        for key in self.ip_format_list:
            tempkey = key.replace("_range", "").replace("_gateway", "").replace("_netmask", "").replace("_vlan", "")
            network_set.add(tempkey)
        return network_set

    def check_network_ip_range(self, input_params, error_msg_dict):
        error_dict = {}
        networks = self.get_network_set()
        for params_item in input_params:
            self.params[params_item["key"]] = params_item["value"]
        for network_key in networks:
            manage_net_range, manage_gateway, manage_netmask = self.get_manage_net_params(network_key)
            if manage_net_range not in self.params:
                continue
            # 规划的ip范围和掩码未填写，不做后续检查，避免脚本执行异常
            if manage_net_range in error_msg_dict or manage_netmask in error_msg_dict:
                continue
            if self.params[manage_net_range].find('-') == -1:
                error_dict[manage_net_range] = get_code_msg('626260') % manage_net_range
                err_msg = "Incorrect parameter format of manage_net_range[%s] ." \
                          "The parameter must contain a hyphen (-)." % self.params[manage_net_range]
                logger.error(err_msg)
                continue

            start_addr, end_addr = self.params[manage_net_range].split('-')
            subnet = get_subnet(start_addr, self.params.get(manage_netmask))
            # 检查start ip 和 end ip是否在子网内
            err_msg = self.check_ip_in_subnet(start_addr, end_addr, subnet, manage_net_range)
            error_dict.update(err_msg)

            # 检查网关是否在子网内，以及网关是否被包含在start ip和end ip内
            err_msg = self.check_gateway(manage_gateway, error_msg_dict, subnet, start_addr, end_addr)
            error_dict.update(err_msg)

            # 检查子网网段和掩码是否匹配
            if self.params.get(manage_netmask) and manage_netmask not in error_msg_dict:
                netmask = self.params[manage_netmask]
                if not does_net_match_mask(subnet, netmask):
                    error_dict[manage_netmask] = SUBNET_MASK_ERROR_MSG % (subnet, netmask)
        return error_dict

    def get_manage_net_params(self, network_key):
        manage_net_range = ""
        manage_gateway = ""
        manage_netmask = ""
        for key in self.ip_format_list:
            if network_key == key.replace("_range", ""):
                manage_net_range = key
            elif network_key == key.replace("_gateway", ""):
                manage_gateway = key
            elif network_key == key.replace("_netmask", ""):
                manage_netmask = key
        return manage_net_range, manage_gateway, manage_netmask

    def check_ip_in_subnet(self, start_addr, end_addr, subnet, manage_net_range):
        error_dict = {}
        if start_addr:
            if not (is_ip_in_net(start_addr, subnet)):
                error_dict[manage_net_range] = START_ADDR_MSG % subnet
            elif is_ip_net_ip(start_addr, subnet):
                error_dict[manage_net_range] = START_ADDR_ERROR_MSG % start_addr
        if end_addr:
            if not (is_ip_in_net(end_addr, subnet)):
                error_dict[manage_net_range] = END_ADDR_MSG % subnet
            elif is_ip_broadcast_ip(end_addr, subnet):
                error_dict[manage_net_range] = END_ADDR_ERROR_MSG % end_addr
            else:
                if ipaddress.ip_address(start_addr) > ipaddress.ip_address(end_addr):
                    error_dict[manage_net_range] = IP_POOL_ERROR_MSG % (start_addr, end_addr)
        return error_dict

    def check_gateway(self, manage_gateway, error_msg_dict, subnet, start_addr, end_addr):
        error_dict = {}
        if self.params.get(manage_gateway) and manage_gateway not in error_msg_dict:
            gateway = self.params[manage_gateway]
            if not (is_ip_in_net(gateway, subnet)):
                error_dict[manage_gateway] = GW_ERROR_NOCONTAIN % subnet
            elif is_ip_net_ip(gateway, subnet):
                error_dict[manage_gateway] = GW_NET_ERROR_MSG % gateway
            elif is_ip_broadcast_ip(gateway, subnet):
                error_dict[manage_gateway] = GW_BROADCAST_ERROR_MSG % gateway

            if end_addr and manage_gateway not in error_msg_dict:
                section = start_addr + '-' + end_addr
                if is_ip_in_section(gateway, section):
                    error_dict[manage_gateway] = GW_ERROR_CONTAIN % (gateway, section)
        return error_dict


class PoolCheck(object):
    def __init__(self):
        self.min_disk_num = 0
        self.max_disk_num = 0
        self.disk_num = 0

    def record_disk_num(self, disk_num):
        if self.min_disk_num == 0:
            self.min_disk_num = disk_num
        else:
            if disk_num < self.min_disk_num:
                self.min_disk_num = disk_num

        if self.max_disk_num == 0:
            self.max_disk_num = disk_num
        else:
            if disk_num > self.max_disk_num:
                self.max_disk_num = disk_num

        self.disk_num += disk_num

    def check_disk_num(self, pool_name):
        ret_msg = dict()
        disk_info = "Disk num of %s: min_disk_num:%s, max_disk_num:%s, disk_num:%s" % (
            pool_name, self.min_disk_num, self.max_disk_num, self.disk_num)
        logger.info(disk_info)
        if self.max_disk_num - self.min_disk_num > 2:
            err_msg = "The difference between maximal[%s] and minimal[%s] main " \
                      "storage number is more than 2." % (self.max_disk_num, self.min_disk_num)
            logger.error(err_msg)
            ret_msg['626268:{}'.format(pool_name)] = get_code_msg('626268') % pool_name
        percentage = (self.max_disk_num - self.min_disk_num) / float(self.max_disk_num)
        if percentage > 0.3:
            percentage = percentage * 100
            err_msg = "The difference[%s%%] between maximal and minimal main storage number is " \
                      "more than 30%% of maximax number." % percentage
            logger.error(err_msg)
            ret_msg['626269:{}'.format(pool_name)] = get_code_msg('626269') % pool_name
        if self.disk_num < 12:
            err_msg = "The total main storage number is less than 12."
            logger.error(err_msg)
            ret_msg['626270:{}'.format(pool_name)] = get_code_msg('626270') % pool_name
        return ret_msg


class BusinessParametersCheckUtils(object):
    def __init__(self):
        pass

    @staticmethod
    def check_system_user_info(project_id, param_item, error_dict):
        msg_dict = {}
        if "creuser" in error_dict:
            return msg_dict
        product_account_white_list = DeployConstant.ACCOUNT_WHITE_LIST
        system_account_password_list = param_item["creuser"].split(",")
        # 系统帐户密码不是两组帐户时出错
        if len(system_account_password_list) != 4:
            msg_dict["system_account_password"] = get_code_msg('626020') % "system_account_password"
            return msg_dict

        # 系统帐户密码的第一个必须是root帐户
        if system_account_password_list[0] != 'root':
            msg_dict["system_account_password"] = get_code_msg('626021') % "system_account_password"
            return msg_dict

        # 系统用户不能是产品内置用户
        if get_project_condition_boolean(project_id, 'TenantStorFB80&!TenantStorFB_Heterogeneous'):
            com_user = system_account_password_list[2]
            if com_user in product_account_white_list:
                msg_dict["system_account_password"] = get_code_msg('626106') % (com_user, product_account_white_list)
        return msg_dict

    def storage_pool_params_check(self, storage_pool_name_list, osd_node_list, disk_type, support_cache):
        error_dict = {}
        for pool in storage_pool_name_list:
            primary_disk_type = None
            pool_redundancy_policy = None
            cache_type = None
            ec_data_fragments = None
            ec_verify_fragments = None
            for osd_node_item in osd_node_list:
                if pool != osd_node_item["storage_pool_name_and_slot"]:
                    continue
                # 主存盘类型检查
                logger.info("start to check primary disk type")
                msg_dict, primary_disk_type = self.primary_disk_type_check(
                    osd_node_item, primary_disk_type, disk_type, error_dict)
                error_dict.update(msg_dict)
                logger.info("check primary disk type complete, result: {}".format(msg_dict))
                # 缓存类型检查
                msg_dict, cache_type = self.cache_type_check(osd_node_item, support_cache, cache_type, error_dict)
                error_dict.update(msg_dict)
                # 存储资源池冗余策略检查
                msg_dict, pool_redundancy_policy = self.redundancy_policy_check(
                    osd_node_item, pool, pool_redundancy_policy, error_dict)
                error_dict.update(msg_dict)
                # ec数据分片检查
                msg_dict, ec_data_fragments = self.ec_data_fragment_check(osd_node_item, ec_data_fragments, error_dict)
                error_dict.update(msg_dict)
                # ec校验分片检查
                msg_dict, ec_verify_fragments = self.ec_verify_fragment_check(
                    osd_node_item, ec_verify_fragments, error_dict)
                error_dict.update(msg_dict)
        return error_dict

    @staticmethod
    def rack_status_and_node_number_check(fb_rack_ha, pool_info_list, input_params):
        """ 池冗余策略：默认为副本；安全级别：机柜；
            副本数：默认3；要求机柜数量必须大于等于4；服务器数量必须大于等于12；
            存储池中机柜数不能大于32；单个机柜中的服务器数不能大于24
            """
        err_msg = {}
        if not fb_rack_ha:
            return err_msg
        for pool_info in pool_info_list:
            redundancy_policy = [
                input_param.get("storagepool_redundancy_policy") for input_param in input_params
                if input_param.get('storage_pool_name_and_slot') == pool_info['name']
            ][0]
            if redundancy_policy.upper() == 'EC':
                logger.info('pool:{}, redundancy policy:{}'.format(pool_info['name'], redundancy_policy))
                continue
            # 校验单个存储池中机柜数量
            logger.info("pool data:%s" % pool_info)
            if len(pool_info["rack_status"]) < 4 or len(pool_info["rack_status"]) > 32:
                err_msg["rack_id_number"] = get_code_msg('626061') % "rack_id_number"
            # 校验机柜中的服务器个数
            for rack_info in pool_info["rack_status"]:
                if int(rack_info["server_num"] < 3) or int(rack_info["server_num"]) > 24:
                    err_msg["server_in_cabinets"] = get_code_msg('626063') % "server_in_cabinets"
            # 校验单个存储池中服务器数量
            if int(pool_info["servers_num"]) < 12:
                err_msg["server_number"] = get_code_msg('626062') % "server"
        return err_msg

    @staticmethod
    def storage_pool_and_backend_pool_name_check(backend_pool_list, storage_pool_name_list):
        output = {}
        if not backend_pool_list or not storage_pool_name_list:
            return True, output
        backend_unfurl_pool_list = list()
        for backend_pools in backend_pool_list:
            backend_pools_list = backend_pools.split(',')
            backend_unfurl_pool_list.extend(backend_pools_list)
        # 检查1.2 business_storage_pool_x与FusionStorageparameters里存储池名的个数是否一致
        if len(backend_unfurl_pool_list) != len(storage_pool_name_list):
            storage_pool_data = "storage_pool_name_and_slot:%s" % ",".join(storage_pool_name_list)
            backend_pool_data = "business_storage_pool:%s" % ",".join(backend_unfurl_pool_list)
            output["storage_pool_name_and_slot and business_storage_pool"] = \
                get_code_msg('626022') % (storage_pool_data, backend_pool_data)
            return False, output
        # 检查1.2与FusionStorageparameters里存储池名是否一致
        for name in backend_unfurl_pool_list:
            same_flag = "False"
            for pool_name in storage_pool_name_list:
                if name.strip() == pool_name.strip():
                    same_flag = "True"
                    logger.info("The pool_name:%s in FusionStorageparameters is exist in Basic_Parameters" % pool_name)
            if same_flag != "True":
                err_msg = "The pool_name in FusionStorage parameters must be smae with Basic_Parameters"
                logger.error(err_msg)
                storage_pool_data = "storage_pool_name_and_slot:%s" % ",".join(storage_pool_name_list)
                backend_pool_data = "business_storage_pool:%s" % ",".join(backend_unfurl_pool_list)
                output["storage_pool_name_and_slot and business_storage_pool"] = \
                    get_code_msg('626022') % (storage_pool_data, backend_pool_data)
                return False, output
        return True, output

    @staticmethod
    def check_threetier_vlan(project_id, params, error_params):
        storage_vlan_key = "fusionstorage_service_vlan"
        error_dic = {}
        if storage_vlan_key in error_params:
            return error_dic
        # 获取计算节点vlan信息
        compute_vlan = params.get("service_storage_data_vlan_id", None)
        storage_vlan = params.get(storage_vlan_key, None)
        if compute_vlan and storage_vlan:
            if get_project_condition_boolean(project_id, "TenantStor_ThreeTierNetwork"):
                if storage_vlan == compute_vlan:
                    error_dic[storage_vlan_key] = get_code_msg('626204') % storage_vlan_key
            else:
                if storage_vlan != compute_vlan:
                    error_dic[storage_vlan_key] = get_code_msg('626205') % storage_vlan_key
                # 获取计算节点网段信息
        return error_dic

    @staticmethod
    def zk_slot_check(param_item, zk_slot, error_dict):
        msg_dict = {}
        # zk槽位是否填写检查
        if not param_item.get("zk_slot"):
            msg_dict["zk_slot"] = get_code_msg('626207')
            return msg_dict, zk_slot

        # zk节点zk槽位格式检测
        if not str(param_item["zk_slot"]).isdigit() and "zk_slot" not in error_dict:
            msg_dict["zk_slot"] = get_code_msg('626209')
            return msg_dict, zk_slot

        # zk节点zk槽位一致性检测
        if not zk_slot:
            zk_slot = param_item["zk_slot"]
        if zk_slot != param_item["zk_slot"] and "zk_slot" not in error_dict:
            msg_dict["zk_slot"] = get_code_msg('626208')
        return msg_dict, zk_slot

    @staticmethod
    def primary_slot_check(param_item, error_dict):
        msg_dict = {}
        # 主存槽位是否填写检测
        if not param_item.get("primary_slot"):
            msg_dict["primary_slot"] = get_code_msg('626212')
            return msg_dict
        if "primary_slot" in error_dict:
            return msg_dict

        # 主存槽位格式检查
        pattern = re.compile("^(?:[0-9]{1}|[1-9]{1}\d+)-\d+$")
        primary_slot = param_item["primary_slot"]
        if not pattern.match(primary_slot):
            msg_dict["primary_slot"] = get_code_msg('626213')
            return msg_dict

        # 单个节点槽位数量检查
        start_slot, end_slot = primary_slot.split("-")
        if int(end_slot) - int(start_slot) < 3:
            msg_dict["primary_slot"] = get_code_msg('626213')
        return msg_dict

    @staticmethod
    def primary_disk_type_check(param_item, primary_disk_type, disk_type, error_dict):
        msg_dict = {}
        if error_dict.get("primary_type"):
            return msg_dict, primary_disk_type
        if not param_item.get("primary_type"):
            msg_dict["primary_type"] = get_code_msg(626344)
            return msg_dict, primary_disk_type
        if primary_disk_type is None:
            primary_disk_type = param_item["primary_type"]
        if primary_disk_type not in disk_type or primary_disk_type != param_item["primary_type"]:
            msg_dict["primary_type"] = get_code_msg(626345) % disk_type
        return msg_dict, primary_disk_type

    @staticmethod
    def cache_type_check(param_item, support_cache, cache_type, error_dict):
        msg_dict = {}
        if error_dict.get("cache_type"):
            return msg_dict, cache_type
        if cache_type is None:
            cache_type = param_item.get("cache_type")
        if cache_type not in support_cache or cache_type != param_item.get("cache_type"):
            msg_dict["cache_type"] = get_code_msg(626012) % support_cache
        return msg_dict, cache_type

    @staticmethod
    def zk_disk_type_check(param_item, zk_type, disk_type, error_dict):
        msg_dict = {}
        if error_dict.get("zk_type"):
            return msg_dict, zk_type
        if not param_item.get("zk_type"):
            msg_dict["zk_type"] = get_code_msg(626347)
            return msg_dict, zk_type
        if param_item["zk_type"] not in disk_type:
            msg_dict["zk_type"] = get_code_msg(626343) % disk_type
            return msg_dict, zk_type
        if not zk_type:
            zk_type = param_item["zk_type"]
        if zk_type != param_item["zk_type"]:
            msg_dict["zk_type"] = get_code_msg(626343) % disk_type
        return msg_dict, zk_type

    @staticmethod
    def redundancy_policy_check(param_item, pool, redundancy_policy, error_dict):
        msg_dict = {}
        if error_dict.get("storagepool_redundancy_policy"):
            return msg_dict, redundancy_policy
        if redundancy_policy is None:
            redundancy_policy = param_item["storagepool_redundancy_policy"]
        if redundancy_policy != param_item["storagepool_redundancy_policy"]:
            msg_dict["storagepool_redundancy_policy"] = get_code_msg('626013') % pool
        return msg_dict, redundancy_policy

    @staticmethod
    def ec_data_fragment_check(param_item, ec_data_fragments, error_dict):
        msg_dict = {}
        if param_item["storagepool_redundancy_policy"].upper() != "EC" or error_dict.get("ec_data_fragments"):
            return msg_dict, ec_data_fragments
        if ec_data_fragments is None:
            ec_data_fragments = param_item.get("ec_data_fragments")
        if ec_data_fragments != param_item.get("ec_data_fragments"):
            msg_dict["ec_data_fragments"] = get_code_msg(626092)
        return msg_dict, ec_data_fragments

    @staticmethod
    def ec_verify_fragment_check(param_item, ec_verify_fragments, error_dict):
        msg_dict = {}
        if param_item["storagepool_redundancy_policy"].upper() != "EC" or error_dict.get("ec_verify_fragments"):
            return msg_dict, ec_verify_fragments
        if ec_verify_fragments is None:
            ec_verify_fragments = param_item.get("ec_verify_fragments")
        if ec_verify_fragments != param_item.get("ec_verify_fragments"):
            msg_dict["ec_verify_fragments"] = get_code_msg(626094)
        return msg_dict, ec_verify_fragments

    @staticmethod
    def all_flash_primary_type_check(node_info, error_dict):
        msg_dict = {}
        for param_item in node_info:
            if error_dict.get("primary_type") or error_dict.get("cache_type"):
                break
            if param_item.get("cache_type") != 'none':
                break
            if param_item.get("primary_type") not in DeployConstant.LLD_DISK_TYPE[2:]:
                msg_dict["primary_type"] = get_code_msg(626348) % DeployConstant.LLD_DISK_TYPE[2:]
        return msg_dict

    @staticmethod
    def zk_slot_and_primary_slot_conflict_check(param_item, error_dict):
        msg_dict = {}
        if "primary_slot" in error_dict or "zk_slot" in error_dict:
            return msg_dict
        zk_slot = param_item.get("zk_slot")
        if not zk_slot:
            return msg_dict
        primary_slot = param_item.get("primary_slot")
        primary_slot_start, primary_slot_end = primary_slot.split('-')
        if int(primary_slot_start) <= int(zk_slot) <= int(primary_slot_end):
            msg_dict["primary_slot"] = get_code_msg('626208')
        return msg_dict

    @staticmethod
    def hostname_check(param_item, hostname, error_dict):
        msg_dict = {}
        if "hostname" in error_dict:
            return msg_dict
        hostname["node_num"] += 1
        hostname["hostname_set"].add(param_item.get('hostname'))
        if hostname["node_num"] != len(hostname["hostname_set"]):
            msg_dict["hostname"] = get_code_msg('626108') % hostname["hostname_set"]
        return msg_dict

    @staticmethod
    def get_rack_ha_pool_info_list(param_item, storage_pool_name, storage_pool_name_set, pool_info_list):
        """
        :param param_item:
        :param storage_pool_name:
        :param storage_pool_name_set:
        :param pool_info_list:
        :return: 存储池信息列表pool_info_list = [存储池信息字典1pool_info_dict1, 存储池信息字典2, ...]
                存储池信息字典pool_info_dict {
                            存储池名称name: "storage_pool_name1",
                            高可用状态rack_status: [rack_status1, rack_status2],
                            服务器数量servers_num: 1
                            }
                高可用状态 rack_status= {"rack_id高可用id": 'abc', "server_num": 1}
        """
        pool_info_dict = {}
        if storage_pool_name not in storage_pool_name_set:
            rack_status = dict()
            pool_info_dict["name"] = storage_pool_name
            pool_info_dict["rack_status"] = []
            rack_status['rack_id'] = param_item["rack_id"]
            rack_status['server_num'] = 1
            pool_info_dict["rack_status"].append(rack_status)
            pool_info_dict["servers_num"] = 1
            pool_info_list.append(pool_info_dict)
            return pool_info_list
        # 刷新pool_info_list，存储池名称固定
        for pool_info in pool_info_list:
            if storage_pool_name != pool_info.get("name"):
                continue
            # 存储池服务器数+1
            pool_info["servers_num"] += 1
            # 判断机柜信息是否存在，不存在则进行记录
            logger.info("pool info data:%s" % pool_info)
            rack_id_list = [rack_info.get("rack_id") for rack_info in pool_info.get("rack_status")]
            if param_item["rack_id"] not in rack_id_list:
                status = dict()
                status['rack_id'] = param_item["rack_id"]
                status['server_num'] = 1
                pool_info["rack_status"].append(status)
                logger.info("add new rack id:%s" % status)
                continue
            for rack_info in pool_info["rack_status"]:
                rack_id_list.append(rack_info["rack_id"])
                if rack_info["rack_id"] == param_item["rack_id"]:
                    rack_info["server_num"] += 1
                    logger.info("The rack[%s] increases by 1." % rack_info)
                    break
        return pool_info_list

    @staticmethod
    def get_backend_pool(project_id, input_params):
        logger.info("Start to query list of backend pool")
        backend_pool_list = list()
        if not input_params:
            return backend_pool_list
        backend_count = BusinessParametersCheckUtils.get_business_backend_count(project_id)
        logger.info('backend count: %s' % backend_count)
        business_pool_key_list = list()
        for index in range(1, backend_count + 1):
            if index == 1:
                business_pool_key_list.append("business_storage_pool")
            else:
                business_pool_key_list.append('{}_{}'.format("business_storage_pool", index))
        logger.info("backend key list:%s" % business_pool_key_list)
        for param_item in input_params:
            if param_item['key'] in business_pool_key_list:
                backend_pool_list.append(param_item['value'])
        logger.info("")
        logger.info("backend value list:%s" % business_pool_key_list)
        return backend_pool_list

    @staticmethod
    def get_business_backend_count(project_id):
        project_conditions = get_project_conditions(project_id)
        backend_count = 1
        for index in range(2, DeployConstant.MAX_BUSINESS_BACKEND + 1):
            if project_conditions.get('MultiTenantFB80StoragePool{}'.format(index)):
                backend_count += 1
            else:
                break
        return backend_count


class ManageStorageParamsCheckUtils(object):
    def __init__(self):
        pass

    @staticmethod
    def not_ha_primary_capacity_check(param_item, primary_capacity, err_msg_dict):
        msg_dict = {}
        if not param_item["primary_capacity"]:
            msg_dict["managestorfb_primary_capacity"] = get_code_msg("626230")
        else:
            if "managestorfb_primary_capacity" not in err_msg_dict:
                if 0 == primary_capacity:
                    primary_capacity = param_item["primary_capacity"]
                elif primary_capacity != param_item["primary_capacity"]:
                    msg_dict["managestorfb_primary_capacity"] = get_code_msg("626231")
        return primary_capacity, msg_dict

    @staticmethod
    def not_ha_cache_check(param_item, manage_cache_type, cache_type, cache_capacity, err_msg_dict):
        cur_err_msg_dict = {}
        if err_msg_dict.get("managestorfb_cache_type") or err_msg_dict.get("managestorfb_cache_capacity"):
            return cache_type, cache_capacity, cur_err_msg_dict
        if cache_type is None:
            cache_type = param_item["cache_type"]
        if param_item["cache_type"] not in manage_cache_type or param_item["cache_type"] != cache_type:
            cur_err_msg_dict["managestorfb_cache_type"] = get_code_msg('626236') % manage_cache_type
            return cache_type, cache_capacity, cur_err_msg_dict
        if param_item["cache_type"] == 'none':
            return cache_type, cache_capacity, cur_err_msg_dict
        if cache_capacity is None:
            cache_capacity = param_item["cache_capacity"]
        elif param_item["cache_capacity"] != cache_capacity:
            cur_err_msg_dict["managestorfb_cache_capacity"] = get_code_msg("626233")
        return cache_type, cache_capacity, cur_err_msg_dict

    @staticmethod
    def not_ha_primary_slot_check(param_item, error_dict):
        msg_dict = {}
        # 主存槽位是否填写检测
        if not param_item.get("primary_slot"):
            msg_dict["managestorfb_primary_slot"] = get_code_msg("626234")
            return msg_dict
        if "managestorfb_primary_slot" in error_dict:
            return msg_dict
        # 主存槽位格式检查
        pattern = re.compile("^(?:[0-9]{1}|[1-9]{1}\d+)-\d+$")
        primary_slot = param_item["primary_slot"]
        if not pattern.match(primary_slot):
            msg_dict["managestorfb_primary_slot"] = get_code_msg("626235")
            return msg_dict

        # 单个节点槽位数量检查
        start_slot, end_slot = primary_slot.split("-")
        if int(end_slot) - int(start_slot) < 3:
            msg_dict["managestorfb_primary_slot"] = get_code_msg("626235")
        return msg_dict

    @staticmethod
    def zk_slot_check(param_item, zk_slot, error_dict):
        msg_dict = {}
        if not param_item["zk_slot"]:
            return zk_slot, msg_dict

        # zk节点zk槽位格式检测
        if not str(param_item["zk_slot"]).isdigit() and "managestorfb_zk_slot" not in error_dict:
            msg_dict["managestorfb_zk_slot"] = get_code_msg("626228")
            return zk_slot, msg_dict

            # zk节点zk槽位一致性检测
        if not zk_slot:
            zk_slot = param_item["zk_slot"]
        if zk_slot != param_item["zk_slot"] and "managestorfb_zk_slot" not in error_dict:
            msg_dict["managestorfb_zk_slot"] = get_code_msg("626229")
        return zk_slot, msg_dict

    @staticmethod
    def zk_slot_and_primary_slot_conflict_check(param_item, error_dict):
        msg_dict = {}
        if "managestorfb_primary_slot" in error_dict or "managestorfb_zk_slot" in error_dict:
            return error_dict
        zk_slot = param_item.get("zk_slot")
        if not zk_slot:
            return msg_dict
        primary_slot = param_item.get("primary_slot")
        primary_slot_start, primary_slot_end = primary_slot.split('-')
        if int(primary_slot_start) <= int(zk_slot) <= int(primary_slot_end):
            msg_dict["managestorfb_conflict_slot"] = get_code_msg("626229")
        return msg_dict

    @staticmethod
    def dc_check_primary_slot(param_item, err_msg_dict, site_name, key_name):
        # 主存槽位的检测
        msg_dict = {}
        if not param_item.get("primary_slot"):
            msg_dict[key_name] = get_code_msg('626248') % site_name
            return msg_dict
        if "primary_slot" in err_msg_dict:
            return msg_dict

        # 主存槽位格式检查
        pattern = re.compile("^(?:[0-9]{1}|[1-9]{1}\d+)-\d+$")
        primary_slot = param_item["primary_slot"]
        if not pattern.match(primary_slot):
            msg_dict["primary_slot"] = get_code_msg('626249') % site_name
            return msg_dict

        # 单个节点槽位数量检查
        start_slot, end_slot = primary_slot.split("-")
        if int(end_slot) - int(start_slot) < 3:
            msg_dict["primary_slot"] = get_code_msg('626249') % site_name
        return msg_dict

    @staticmethod
    def dc_check_primary_capacity(param_item, err_msg_dict, site_name, key_name, primary_capacity):
        # 主存盘容量的检测
        msg_dict = {}
        if not param_item["primary_capacity"]:
            msg_dict[key_name] = get_code_msg('626243') % site_name
        else:
            if key_name not in err_msg_dict:
                if primary_capacity == 0:
                    primary_capacity = param_item["primary_capacity"]
                elif primary_capacity != param_item["primary_capacity"]:
                    msg_dict[key_name] = get_code_msg('626244') % site_name
        return primary_capacity, msg_dict

    @staticmethod
    def dc_check_cache_type(param_item, manage_cache_type, cache_type, site, err_msg_dict, err_key):
        msg_dict = {}
        if err_msg_dict.get(err_key):
            return cache_type, msg_dict
        if cache_type is None:
            cache_type = param_item["cache_type"]
        elif param_item["cache_type"] not in manage_cache_type or cache_type != param_item["cache_type"]:
            msg_dict[err_key] = get_code_msg('626247') % (manage_cache_type, site)
        return cache_type, msg_dict

    @staticmethod
    def dc_check_cache_capacity(param_item, err_msg_dict, site_name, cache_capacity, capacity_key_name, type_key_name):
        # 缓存（卡、盘）总容量(GB)的检测
        msg_dict = {}
        if param_item["cache_type"] == 'none' or err_msg_dict.get(type_key_name) or err_msg_dict.get(capacity_key_name):
            return None, msg_dict
        if not param_item["cache_capacity"]:
            msg_dict[capacity_key_name] = get_code_msg('626245') % site_name
        else:
            if cache_capacity == 0:
                cache_capacity = param_item["cache_capacity"]
            elif cache_capacity != param_item["cache_capacity"]:
                msg_dict[capacity_key_name] = get_code_msg('626246') % site_name
        return cache_capacity, msg_dict

    @staticmethod
    def check_region_ha_pool_disk_num(site, pool, server_list):
        pool_check = PoolCheck()
        for server in server_list:
            if not ("first_node" in server["bmc_role"] or "controller" in server["bmc_role"] or
                    ("cloud_service" in server["bmc_role"] and "osd" in server["ref_component"])):
                continue
            if server["site"] != site:
                continue
            disk_slot = server["primary_slot"]
            if disk_slot:
                disk_num = int(disk_slot.split('-')[1]) - int(disk_slot.split('-')[0]) + 1
                pool_check.record_disk_num(disk_num)
        return pool_check.check_disk_num(pool)


class TenantStorFBHCIParamsCheckUtils(object):
    def __init__(self):
        pass

    @staticmethod
    def zk_slot_check(param_item, zk_slot, error_dict):
        msg_dict = {}
        if not param_item["zk_slot"]:
            msg_dict["tenantstorfbhci_zk_slot"] = get_code_msg('626215')
            return zk_slot, msg_dict

        # zk节点zk槽位格式检测
        if not str(param_item["zk_slot"]).isdigit() and "tenantstorfbhci_zk_slot" not in error_dict:
            msg_dict["tenantstorfbhci_zk_slot"] = get_code_msg("626216")
            return zk_slot, msg_dict

        # zk节点zk槽位一致性检测
        if not zk_slot:
            zk_slot = param_item["zk_slot"]
        if zk_slot != param_item["zk_slot"] and "tenantstorfbhci_zk_slot" not in error_dict:
            msg_dict["tenantstorfbhci_zk_slot"] = get_code_msg("626217")
        return zk_slot, msg_dict

    @staticmethod
    def primary_slot_check(param_item, error_dict):
        msg_dict = {}
        # 主存槽位是否填写检测
        if not param_item.get("primary_slot"):
            msg_dict["tenantstorfbhci_primary_slot"] = get_code_msg("626218")
            return msg_dict
        if "tenantstorfbhci_primary_slot" in error_dict:
            return msg_dict
        # 主存槽位格式检查
        pattern = re.compile("^(?:[0-9]{1}|[1-9]{1}\d+)-\d+$")
        primary_slot = param_item["primary_slot"]
        if not pattern.match(primary_slot):
            msg_dict["tenantstorfbhci_primary_slot"] = get_code_msg("626219")
            return msg_dict
        # 单个节点槽位数量检查
        start_slot, end_slot = primary_slot.split("-")
        if int(end_slot) - int(start_slot) < 3:
            msg_dict["tenantstorfbhci_primary_slot"] = get_code_msg("626219")
        return msg_dict

    @staticmethod
    def primary_capacity_check(param_item, primary_capacity, err_msg_dict):
        msg_dict = {}
        if not param_item["primary_capacity"]:
            msg_dict["tenantstorfbhci_primary_capacity"] = get_code_msg('626220')
        else:
            if "tenantstorfbhci_primary_capacity" not in err_msg_dict:
                if 0 == primary_capacity:
                    primary_capacity = param_item["primary_capacity"]
                elif primary_capacity != param_item["primary_capacity"]:
                    msg_dict["tenantstorfbhci_primary_capacity"] = get_code_msg('626221')
        return primary_capacity, msg_dict

    @staticmethod
    def cache_type_check(param_item, cache_type, err_msg_dict):
        msg_dict = {}
        if not param_item["cache_type"]:
            err_msg_dict["tenantstorfbhci_cache_type"] = get_code_msg('626222')
        else:
            if "tenantstorfbhci_cache_type" not in err_msg_dict:
                if not cache_type:
                    cache_type = param_item["cache_type"]
                elif cache_type != param_item["cache_type"]:
                    err_msg_dict["tenantstorfbhci_cache_type"] = get_code_msg('626223')
        return cache_type, msg_dict

    @staticmethod
    def cache_capacity_check(param_item, cache_capacity, err_msg_dict):
        msg_dict = {}
        if not param_item["cache_capacity"]:
            msg_dict["tenantstorfbhci_cache_capacity"] = get_code_msg('626224')
        else:
            if "tenantstorfbhci_cache_capacity" not in err_msg_dict:
                if 0 == cache_capacity:
                    cache_capacity = param_item["cache_capacity"]
                elif cache_capacity != param_item["cache_capacity"]:
                    msg_dict["tenantstorfbhci_cache_capacity"] = get_code_msg('626225')
        return cache_capacity, msg_dict

    @staticmethod
    def zk_slot_and_primary_slot_conflict_check(param_item, error_dict):
        msg_dict = {}
        if "tenantstorfbhci_primary_slot" in error_dict or "tenantstorfbhci_zk_slot" in error_dict:
            return error_dict
        zk_slot = param_item.get("zk_slot")
        if not zk_slot:
            return msg_dict
        primary_slot = param_item.get("primary_slot")
        primary_slot_start, primary_slot_end = primary_slot.split('-')
        if int(primary_slot_start) <= int(zk_slot) <= int(primary_slot_end):
            msg_dict["managestorfb_conflict_slot"] = get_code_msg("626216")
        return msg_dict
