# -*- coding: utf-8 -*-
import traceback
from utils.common.fic_base import TestCase
import utils.common.log as logger
from utils.common.message import Message
from utils.common.exception import FCDException
from plugins.DistributedStorage.scripts.logic.DeployOperate import DeployOperate
from plugins.DistributedStorage.scripts.utils.common.DeployConstant import DeployConstant
from utils.client.FSPAuthClient import FSPAuthClient
from utils.Driver.CloudDC.OpenStack.get_host_info import GetHostInfo
from utils.constant.FCDConstant import BMC_ROLE_INFO


class CreateCluster(TestCase):
    def __init__(self, project_id, pod_id, fs_args, condition=None, metadata=None, **kwargs):
        super(CreateCluster, self).__init__(project_id, pod_id)
        self.fs_args = fs_args
        self.opr = DeployOperate(self.fs_args)
        self.first_metadata_node = None
        self.first_metadata_type = None
        self.first_metadata_size = None
        self.all_flash = False
        self.condition = condition
        self.metadata = metadata
        self.more_args = kwargs

    def procedure(self):
        try:
            logger.info("Start to create cluster.")
            self.opr.login(DeployConstant.DM_LOGIN_USER, self.fs_args['dm_update_pwd'])
            logger.info("Check fs conf paramters.")
            cluster_ip_list, zk_slot = self.get_cluster_list()

            logger.info('Creating cluster')
            cluster_name = 'cluster01'
            server_list = list()
            res = self.opr.scan_server_media(cluster_ip_list)
            for ip in cluster_ip_list:
                media_data = res.get_media_by_node_slot(ip, zk_slot, self.all_flash)
                if not media_data:
                    err_msg = "Failed to get media by slot[%s] on node[%s]. Media detail:%s" % (zk_slot, ip, media_data)
                    logger.error(err_msg)
                    raise Exception(err_msg)

                if not self.first_metadata_node:
                    self.first_metadata_node = ip
                media_type = media_data.get('mediaType')
                self.compare_with_first_value(media_type, self.first_metadata_type, 'type', ip)
                media_size = media_data.get('mediaSize')
                self.compare_with_first_value(media_size, self.first_metadata_size, 'size', ip)
                media_status = media_data.get('mediaRole')
                if media_status != 'no_use':
                    err_msg = "Failed to get media by slot[%s] on node[%s]. " \
                              "The disk of slot is not exist" % (zk_slot, ip)
                    logger.error(err_msg)
                    raise Exception(err_msg)

                if media_type == 'ssd_card':
                    zk_disk_esn = media_data.get('phyDevEsn')
                    server = {'nodeMgrIp': ip, 'zkType': media_type, 'zkDiskSlot': zk_slot, 'zkDiskEsn': zk_disk_esn}
                else:
                    server = {'nodeMgrIp': ip, 'zkType': media_type, 'zkDiskSlot': zk_slot}
                server_list.append(server)
            res = self.opr.create_cluster(cluster_name, server_list)
            result, res_detail = res.get_query_detail()
            if result != 0:
                err_msg = "Failed to Create Cluster, Result:%s, Detail:%s" % (result, res_detail)
                logger.error(err_msg)
                raise Exception(err_msg)

            logger.info('Create cluster successful')
            self.opr.login_out(DeployConstant.DM_LOGIN_USER, self.fs_args['dm_update_pwd'])
        except FCDException as e:
            logger.error(traceback.format_exc())
            return Message(500, e)
        except Exception as e:
            return Message(500, FCDException(626002, str(e)))
        return Message()

    def get_cluster_list(self):
        nodes = self.db.get_bmc_info_by_pod_id(pod_id=self.pod_id)
        webui_client = FSPAuthClient.get_cps_web_client(
            self.db, self.project_id, self.pod_id)
        self.getHostInfo = GetHostInfo(webui_client)
        # 获取元数据节点bmcip
        cluster_bmc_ip_list = [unit['bmc_ip'].split('/')[0] for unit
                               in nodes if unit["is_metadata_node"] == "1"
                               and (BMC_ROLE_INFO.KVM in unit["bmc_role"].split(',')
                               or BMC_ROLE_INFO.KVM_DPDK in unit["bmc_role"].split(','))]
        # 获取元数据节点主存槽位
        primary_slot_list = [unit['primary_slot'].split('/')[0] for unit
                             in nodes if unit["is_metadata_node"] == "1"
                             and (BMC_ROLE_INFO.KVM in unit["bmc_role"].split(',')
                             or BMC_ROLE_INFO.KVM_DPDK in unit["bmc_role"].split(','))]
        # 获取元数据槽位
        zk_slot_list = [unit['zk_slot'].split('/')[0] for unit
                        in nodes if unit["is_metadata_node"] == "1"
                        and (BMC_ROLE_INFO.KVM in unit["bmc_role"].split(',')
                        or BMC_ROLE_INFO.KVM_DPDK in unit["bmc_role"].split(','))]
        cache_type_list = [unit['cache_type'].split('/')[0] for unit in nodes if unit["is_metadata_node"] == '1']
        # 获取元数据节点管理ip
        cluster_id_list, cluster_ip_list = self.getHostInfo.get_host_info(cluster_bmc_ip_list)
        # 元数据节点个数检查
        if len(cluster_ip_list) not in [3, 5, 7]:
            logger.error("the num of cluster:%s is wrong" % len(cluster_ip_list))
            raise Exception("the num of cluster:%s is wrong" % len(cluster_ip_list))
        # 元数据节点主存槽位检查
        if len(primary_slot_list) == 0 or not primary_slot_list[0]:
            raise Exception("The primary slot of metadata node in LLD is empty")
        # zk槽位检查
        zk_slot = zk_slot_list[0]
        # zk槽位一致性检查
        for slot in zk_slot_list:
            if zk_slot != slot:
                raise Exception("The slot of zk must be same")
        # zk槽位为空取默认值
        if not zk_slot:
            zk_slot = '2'
        logger.info("all cache type list:%s" % cache_type_list)
        if 'none' in cache_type_list:
            self.all_flash = True
        return cluster_ip_list, zk_slot

    def compare_with_first_value(self, src_value, cmp_value, value_type, node_ip):
        if not cmp_value:
            if value_type == 'type':
                self.first_metadata_type = src_value
            else:
                self.first_metadata_size = src_value
            return
        if src_value != cmp_value:
            err_msg = "The %s of metadata disk on the node[%s] is inconsistent with the first node[%s]." \
                      "Detail: current node:%s,first node:%s" % (value_type, node_ip, self.first_metadata_node,
                                                                 cmp_value, src_value)
            logger.error(err_msg)
            raise Exception(err_msg)
        return
