#!/usr/bin/env python
# -*- coding: utf-8 -*-
import secrets
import re

import utils.common.log as logger
from utils.common import message
from utils.common.fic_base import TestCase
from utils.common.exception import HCCIException
from utils.common.ssh_util import Ssh as SshUtil
from plugins.DistributedStorage.logic.InstallOperate import InstallOperate
from plugins.DistributedStorage.utils.common.DeployConstant import DeployConstant
from plugins.DistributedStorage.Replication.scripts.common_utils.config_params import Params
from plugins.DistributedStorage.Replication.scripts.common_utils.RestOperate import RestOperate


class CreateIpPool_01(TestCase):
    def __init__(self, project_id, pod_id):
        super(CreateIpPool_01, self).__init__(project_id, pod_id)
        self.service_name = "FusionStorageBlockReplication"

    def pre_condition(self):
        pass

    def procedure(self):
        """
        1、查询获取复制两网口[rep0、rep1]的复制IP、mask
        2、调用rest接口，将掩码较小的复制网络信息rep0作为传参，创建IP地址池
        3、调用rest接口查询已创建的ip地址池
        4、根据查询结果，判断rep1是否在IP地址池内，如果没有，调用rest接口添加到IP地址池
        """
        log_module_name = self.args_dict['log_module_name']
        logger.init(log_module_name)
        self.pod_id = self.args_dict['pod_id']
        self.project_id = self.args_dict['project_id']
        try:
            logger.info("[FSBR] Start to create ip address pool.")
            logger.info("[FSBR] Start to get LLD params.")
            # 复制平面的网络信息
            all_params = Params(self.project_id, self.pod_id, self.service_name).get_params_dict()
            cluster_info = all_params.get("replication_cluster_nodes_info")
            node_addr_info = ','.join([info.get('replication_manage_ip') for info in cluster_info])
            ip_pool_name = "ippool" + str(secrets.SystemRandom().choice(list(range(1, 20))))
            ip_pool_port = "12100"
            float_ip = all_params.get('local_storage_fsm_ip')
            cmd_passwd = all_params.get('local_admin_password')
            logger.info("[FSBR] End to get LLD params.")

            logger.info("[FSBR] Start to login fsm. ")
            self.opr = RestOperate(float_ip)
            self.opr.login(DeployConstant.DM_LOGIN_USER, cmd_passwd)

            logger.info("[FSBR] Start to query control cluster id.")
            control_cluster_id = self.query_control_cluster_id()

            logger.info("[FSBR] Start to create IP pool.")
            rep_nick_name0, rep_ip0, rep_mask0, rep_nick_name1, rep_ip1, rep_mask1 = self.get_rep_net_info(cluster_info)
            rep0_num = str(exchange_mask(rep_mask0))
            rep1_num = str(exchange_mask(rep_mask1))
            # 根据掩码位数交换顺序，便于判断大的掩码网段是否被包含在小的掩码网段范围内
            if rep0_num > rep1_num:
                rep_nick_name0, rep_ip0, rep_mask0, rep_nick_name1, rep_ip1, rep_mask1 = \
                    rep_nick_name1, rep_ip1, rep_mask1, rep_nick_name0, rep_ip0, rep_mask0
                rep0_num, rep1_num = rep1_num, rep0_num

            logger.info("[FSBR] rep ip info:[{}，{}，{}], [{}，{}，{}]"
                        "".format(rep_nick_name0, rep_ip0, rep_mask0, rep_nick_name1, rep_ip1, rep_mask1))
            net_mask0 = rep_ip0 + "/" + rep0_num

            self.create_ip_pool(control_cluster_id, ip_pool_name, net_mask0, node_addr_info, ip_pool_port)

            # 查询已加入ip地址池的ip，判断rep_ip1是否也被加入
            self.check_added_rep_ip(control_cluster_id, rep_ip1, rep1_num, node_addr_info, rep_nick_name1)

            logger.info("[FSBR] Create ip address pool success.")
        except HCCIException as e:
            logger.error(e)
            raise Exception(str(e))
        except Exception as e:
            logger.error(e)
            raise Exception(str(e))
        finally:
            self.opr.logout()
        return message.Message(200)

    def query_control_cluster_id(self):
        result = self.opr.query_control_cluster()
        control_cluster_id = result.get_control_cluster_id()
        if not control_cluster_id:
            msg = "[FSBR] Create IP pool fail, not found control cluster id. detail: \n %s" % result.res.json()
            logger.error(msg)
            raise Exception(msg)
        return control_cluster_id

    def create_ip_pool(self, control_cluster_id, ip_pool_name, net_mask0, node_addr_info, ip_pool_port):
        result = self.opr.create_ip_pool(control_cluster_id, ip_pool_name, net_mask0, node_addr_info, ip_pool_port)
        ret_value = result.query_dr_cmd_result()
        if 0 != ret_value:
            msg = "[FSBR] Create ip address pool fail.detail: \n%s" \
                  "" % result.res.json()
            logger.error(msg)
            raise Exception(msg)

    def check_added_rep_ip(self, control_cluster_id, rep_ip1, rep1_num, node_addr_info, rep_nick_name1):
        result = self.opr.query_ip_pool(control_cluster_id)
        ret_value, ip_pool_list = result.query_ip_pool_result()
        if 0 != ret_value:
            msg = "[FSBR] Query ip address pool fail.detail: \n%s" \
                  "" % result.res.json()
            logger.error(msg)
            raise Exception(msg)
        added_ip_list = list()
        for ip_pool_ip in ip_pool_list:
            local_ip_pool_info = ip_pool_ip.split(',')
            for ip_info in local_ip_pool_info:
                ip_str = ip_info.split(':')[1]
                added_ip_list.extend(ip_str.split('@'))
        logger.info('added ip: {}, rep_ip1: {}'.format(
            added_ip_list, rep_ip1))
        if rep_ip1 not in added_ip_list:
            logger.info("[FSBR] start to add ip address pool")
            net_mask1 = rep_ip1 + "/" + rep1_num
            logger.info("[FSBR] rep add ip info: [{} {} {} {}]".format(
                control_cluster_id, net_mask1,
                node_addr_info, rep_nick_name1))
            result = self.opr.add_ip_pool(control_cluster_id, net_mask1,
                                          node_addr_info, rep_nick_name1)
            ret_value = result.query_dr_cmd_result()
            if 0 != ret_value:
                msg = "[FSBR] Add ip address pool fail.detail: \n%s" \
                      "" % result.res.json()
                logger.error(msg)
                raise Exception(msg)

    def get_rep_net_info(self, node_info):
        """
        获取IP对应的网口名称和掩码
        """
        if node_info:
            info = node_info[-1]
            host_ip = info.get("replication_manage_ip")
            rep_ip0, rep_ip1 = info.get("replication_network").split(",")
            root_passwd = info.get("replication_manage_ip_root_password")
            common_user = info.get("replication_manage_ip_common_username")
            common_user_passwd = info.get(
                "replication_manage_ip_common_password")
            client = InstallOperate.create_ssh_root_client(
                host_ip, common_user, common_user_passwd, root_passwd)
            rep_nick_name0, rep_mask0, rep_nick_name1, rep_mask1 = \
                self.get_mask_method(rep_ip0, rep_ip1, client, host_ip)
            if client:
                SshUtil.ssh_close(client)
            return rep_nick_name0, rep_ip0, rep_mask0, rep_nick_name1, rep_ip1, rep_mask1

    def get_mask_method(self, rep_ip0, rep_ip1, client, host_ip):
        """
        查询rep_ip对应的网口名称和掩码
        """
        cmd = "ifconfig |grep -A 1 'rep0'"
        cmd = cmd + ";echo last cmd result: $?\n"
        result0 = SshUtil.ssh_exec_command_return(client, cmd)
        if str(result0).find('last cmd result: 0') < 0:
            msg = "[FSBR] Query rep net mask fail, manage ip:%s," \
                  "rep nick :%s" % (host_ip, 'rep0')
            logger.error(msg)
            raise Exception(msg)
        cmd = "ifconfig |grep -A 1 'rep1'"
        cmd = cmd + ";echo last cmd result: $?\n"
        result1 = SshUtil.ssh_exec_command_return(client, cmd)
        if str(result1).find('last cmd result: 0') < 0:
            msg = "[FSBR] Query rep net mask fail, manage ip:%s," \
                  "rep nick :%s" % (host_ip, 'rep1')
            logger.error(msg)
            raise Exception(msg)
        nick_name0, netmask0 = self.get_rep_nick_name_and_mask(
            [result0, result1], rep_ip0)
        nick_name1, netmask1 = self.get_rep_nick_name_and_mask(
            [result0, result1], rep_ip1)
        return nick_name0, netmask0, nick_name1, netmask1

    def get_rep_nick_name_and_mask(self, result_list, rep_ip):
        result = None
        for result in result_list:
            if str(result).find(rep_ip) >= 0:
                result = str(result)
                break
        if not result:
            msg = "[FSBR] Not found replication ip[%s] network info." % rep_ip
            logger.error(msg)
            raise Exception(msg)
        # 获取网口名称
        nick_name = 'rep' + result.split('rep')[1][0]
        pattern = re.compile("Mask:(.*?) |netmask (.*?) broadcast")
        netmask = pattern.findall(str(result))
        if netmask[0][0]:
            netmask = netmask[0][0]
        else:
            netmask = netmask[0][1] if netmask[0][1] else ""
        if not netmask:
            msg = "[FSBR] Not found replication plane net mask."
            logger.error(msg)
            raise Exception(msg)
        return nick_name.strip(), netmask.strip()

    def post_condition(self):
        pass

    def failure(self):
        pass


def exchange_mask(mask):
    """返回子网掩码的位数，255.255.255.0  返回 16, --> 应该为24吧"""
    def count_bit(bin_str):
        res = len([i for i in bin_str if i == '1'])
        return res
    mask_splited = mask.split('.')
    mask_count = [count_bit(bin(int(i))) for i in mask_splited]
    return sum(mask_count)
