# -*- coding: utf-8 -*-
import traceback
from IPy import IP
from utils.common.fic_base import TestCase
import utils.common.log as logger
from utils.common.message import Message
from utils.common.exception import HCCIException
from plugins.DistributedStorage.logic.DeployOperate import DeployOperate
from plugins.DistributedStorage.utils.common.DeployConstant import DeployConstant
from utils.business.project_condition_utils import get_project_condition_boolean
from utils.Driver.CloudDC.OpenStack.Network.networkutils import ManageMentStorageData


class ConfigStorageNetwork(TestCase):
    def __init__(self, project_id, pod_id, fs_args, condition=None, metadata=None, **kwargs):
        super(ConfigStorageNetwork, self).__init__(project_id, pod_id)
        self.fs_args = fs_args
        self.opr = DeployOperate(self.fs_args)
        self.condition = condition
        self.metadata = metadata
        self.more_args = kwargs
        self.update_pwd = self.fs_args['dm_update_pwd']
        self.fsa_list = self.fs_args['fsa_list']
        self.scenario_extend_condition = get_project_condition_boolean(
            self.project_id,
            'ExpansionAZ_KVM|ExpansionAZ_BMS|ExpansionComputeRes_KVMNode|ExpansionMgmtRes_ServiceNode|'
            'ExpansionScale_CloudServiceNode|ExpansionServiceStorage')

    def procedure(self):
        try:
            logger.info("Start to config storage network.")
            self.opr.login(DeployConstant.DM_LOGIN_USER, self.update_pwd)
            # 参数配置
            eth_port = DeployConstant.MGR_STORAGE_NET_INTF
            logger.info('Get network list')
            network_list = self.get_network_list()

            scenario = self.get_scenario()
            logger.info("Current scenario: %s." % scenario)

            logger.info("Config frontend storage network%s." % network_list)
            self.config_storage_frontend(eth_port, network_list, scenario)

            logger.info("Config backend storage network%s." % network_list)
            net_type = self.config_storage_backend(eth_port, network_list, scenario)
            if not self.fsa_list:
                err_msg = "fsa list is none"
                logger.error(err_msg)
                return Message()
            self.config_net_validity(net_type)

            logger.info("Config storage network finished.")
            self.opr.login_out(DeployConstant.DM_LOGIN_USER, self.update_pwd)
        except HCCIException as e:
            logger.error(traceback.format_exc())
            return Message(500, e)
        except Exception as e:
            logger.error(traceback.format_exc())
            return Message(500, HCCIException(626064, str(e)))
        return Message()

    def config_net_validity(self, net_type):
        node_list = [fsa['om_ip'] for fsa in self.fsa_list]
        rsp = self.opr.config_net_validity(net_type, node_list)
        rsp_code, rsp_data = rsp.get_net_validity_data()
        fail_ip_list = list(rsp_data.keys())
        if rsp_code != 0 or len(fail_ip_list) > 0:
            err_msg = "Failed to config storage network on host%s, Detail:%s" % (fail_ip_list, rsp_data)
            logger.error(err_msg)
            raise Exception(err_msg)

    def config_storage_backend(self, eth_port, network_list, scenario):
        net_type = 'storage_backend'
        res_result, res_data = self.opr.set_net_plane(network_list, net_type, scenario)
        if res_result.get("code") != 0 or res_data is not None:
            err_msg = "Failed to config storage_frontend network[network:%s, nettype:%s, ethname:%s], " \
                      "Detail:[%s]%s" % (network_list, net_type, eth_port, res_result, res_data)
            logger.error(err_msg)
            raise Exception(err_msg)
        return net_type

    def config_storage_frontend(self, eth_port, network_list, scenario):
        net_type = 'storage_frontend'
        res_result, res_data = self.opr.set_net_plane(network_list, net_type, scenario)
        if res_result.get("code") != 0 or res_data is not None:
            err_msg = "Failed to config storage_frontend network[network:%s, nettype:%s, ethname:%s], " \
                      "Detail:[%s]%s" % (network_list, net_type, eth_port, res_result, res_data)
            logger.error(err_msg)
            raise Exception(err_msg)

    def get_scenario(self):
        if self.scenario_extend_condition:
            scenario = 'extend'
        else:
            scenario = 'initialization'
        return scenario

    def get_network_list(self):
        obj = ManageMentStorageData(self.project_id, self.pod_id)
        storage_net_data_list = obj.get_management_storage_data_info()
        network_list = []
        for storage_net_data in storage_net_data_list:
            manage_storage_netmask = storage_net_data.get('net_info_netmask')
            manage_storage_gateway = storage_net_data.get('net_info_gateway')
            manage_net_plane_segment = storage_net_data.get('net_info_range')
            if not manage_storage_netmask or not manage_storage_gateway or not manage_net_plane_segment:
                err_msg = "Failed to obtain network parameters. Check the network parameters in the LLD."
                logger.error(err_msg)
                raise Exception(err_msg)

            manage_net_segment_list = manage_net_plane_segment.split('-')
            manage_net_start = manage_net_segment_list[0]
            manage_net_plane = IP(manage_net_start).make_net(manage_storage_netmask)
            ip_net = IP(manage_net_plane)
            net_segment = ip_net.strNormal(3)
            net_segment_list = net_segment.split('-')
            manage_storage_start_ip = net_segment_list[0]
            manage_storage_end_ip = net_segment_list[1]
            network_info = {'port_name': '',
                            'ip_segment': {'begin_ip': manage_storage_start_ip, 'end_ip': manage_storage_end_ip},
                            'subnet_prefix': manage_storage_netmask,
                            'default_gateway': manage_storage_gateway}
            logger.info("add compute network info: %s" % network_info)
            network_list.append(network_info)
        return network_list
