# -*- coding: utf-8 -*-
import time
import traceback
from tenacity import retry, stop_after_attempt, wait_fixed

from utils.common.fic_base import TestCase
import utils.common.log as logger
from utils.common.message import Message
from plugins.DistributedStorage.scripts.logic.DeployOperate import DeployOperate
from plugins.DistributedStorage.scripts.utils.common.DeployConstant import DeployConstant
from plugins.DistributedStorage.scripts.logic.InstallOperate import InstallOperate


class AddNode(TestCase):
    def __init__(self, project_id, pod_id, fs_args, condition=None, metadata=None, **kwargs):
        super(AddNode, self).__init__(project_id, pod_id)
        self.fs_args = fs_args
        self.opr = DeployOperate(self.fs_args)
        self.install_operate = InstallOperate(self.project_id, self.pod_id, self.fs_args)
        self.condition = condition
        self.metadata = metadata
        self.more_args = kwargs

    def procedure(self):
        try:
            logger.info("Start to add nodes.")
            self.first_login_deploy_manager()

            node_list = list()
            node_deploy_list = list()
            vbs_list = self.fs_args.get('vbs_list')
            self.get_vbs_info(vbs_list, node_list, node_deploy_list)
            logger.info("Get all node list<%s>" % node_list)
            self.install_operate.add_sshd_host_key(node_list)

            logger.info("Checking nodes validity%s" % node_deploy_list)
            self.check_node_validity(node_list)

            logger.info("Adding nodes%s" % (str(node_deploy_list)))
            self.add_node(node_list)
            time.sleep(60)

            logger.info("Install network manage component nodes")
            self.install_manage_component_node(node_deploy_list)
            time.sleep(120)

            logger.info("Query network manage component installation status")
            self.query_component_install_status()

            logger.info('start to config iBMC account information')
            self.config_bmc_account_info()
        except Exception as e:
            logger.error(traceback.format_exc())
            raise Exception(e)
        finally:
            self.opr.login_out(DeployConstant.DM_LOGIN_USER, self.fs_args['dm_update_pwd'])

    def config_bmc_account_info(self):
        """
        配置节点iBMC用户名密码,存储版本宽适配，811、810版本无该接口，配置失败只打印error日志
        """
        server_list = []
        if not self.fs_args.get('vbs_list'):
            return
        for node in self.fs_args.get('vbs_list'):
            cur_node = {
                "management_ip": node.get('om_ip'),
                "user_name": node.get('bmc_name'),
                "password": node.get('bmc_passwd')
            }
            server_list.append(cur_node)
        request_data = {"server_list": server_list}
        try:
            details = self.opr.config_osd_node_bmc_account_info(request_data)
        except Exception as e:
            logger.error('Config iBMC account information failed, Details:{}'.format(e))
        else:
            logger.info('The iBMC account information is configured successfully, Details:{}'.format(details))

    def query_component_install_status(self):
        wait_time = 3600
        task_status = None
        while wait_time > 0:
            res = self.opr.query_task_status('agent')
            status_code, error_code, error_des = res.get_res_code()
            if error_code != 0:
                err_msg = "Failed to query network manage component installation status , Detail:[%s]%s" \
                          % (error_code, error_des)
                logger.error(err_msg)
                raise Exception(err_msg)
            task_status, server_reslut = res.get_res_data()
            if task_status == 'success':
                logger.info("Succeed to install network manage component to all node.Detail:%s" % (server_reslut))
                break
            elif task_status == "failure":
                err_msg = "Failed to install network manage component, Detail:[%s]%s" % (task_status,
                                                                                         str(server_reslut))
                logger.error(err_msg)
                raise Exception(err_msg)
            else:
                logger.info("Processing<%s> to install network manage component on node. Detail:%s"
                            % (task_status, str(server_reslut)))
            time.sleep(30)
            wait_time -= 30
        if wait_time <= 0 and task_status != 'success' and task_status != 'failure':
            err_msg = "Wait for installation end timeout"
            logger.error(err_msg)
            raise Exception(err_msg)

    def first_login_deploy_manager(self):
        res_code = self.opr.first_login(DeployConstant.DM_LOGIN_USER, "", self.fs_args['dm_update_pwd'])
        if res_code != 0:
            err_msg = "Failed to login deploy manager"
            logger.error(err_msg)
            raise Exception(err_msg)

    def get_vbs_info(self, vbs_list, node_list, node_deploy_list):
        for vbs in vbs_list:
            hostname = vbs.get('hostname')
            if hostname == "":
                hostname = ''
            if vbs['rep_ctl'] == "1":
                cur_role = ['compute', 'storage']
            else:
                cur_role = ['compute']

            node_vbs = {"serial_number": "",
                        "name": hostname,
                        "management_internal_ip": vbs['om_ip'],
                        "om_ip": vbs['om_ip'],
                        "role": cur_role,
                        "cabinet": 2,
                        "authentication_mode": "password",
                        "user_name": vbs.get('user'),
                        "password": vbs.get('passwd'),
                        "root_password": vbs.get('root_pwd')}
            node_list.append(node_vbs)
            node_deploy_list.append(vbs.get('om_ip'))

    @retry(stop=stop_after_attempt(3), wait=wait_fixed(3), reraise=True)
    def check_node_validity(self, node_list):
        res = self.opr.node_check_validity('post', node_list)
        ret_code, ret_data = res.get_nodes_data()
        fail_nodes_list = ret_data.get('data').get('failed_nodes')
        success_nodes_list = ret_data.get('data').get('successful_nodes')
        if ret_code != 0 or len(fail_nodes_list) > 0:
            code = ret_data.get('result').get('code')
            err_des = ret_data.get('result').get('code')
            suggestion = ret_data.get('result').get('code')
            err_msg = "Failed to check validity on nodes%s. Succeeful nodes%s. DetaiL:[%s]%s. Suggestion:%s." \
                      % (fail_nodes_list, success_nodes_list, code, err_des, suggestion)
            logger.error(err_msg)
            raise Exception(err_msg)

    def add_node(self, node_list):
        res = self.opr.add_servers('post', node_list, timeout=1900)
        status_code, error_code, error_des = res.get_res_code()
        if error_code != 0:
            err_msg = "Failed to add hosts, Detail:[%s]%s" % (error_code, error_des)
            logger.error(err_msg)
            raise Exception(err_msg)

    def install_manage_component_node(self, node_deploy_list):
        res = self.opr.deploy_service(node_deploy_list, 'agent')
        status_code, error_code, error_des = res.get_res_code()
        if error_code != 0:
            err_msg = "Failed to install network manage component , Detail:[%s]%s" % (error_code, error_des)
            logger.error(err_msg)
            raise Exception(err_msg)

    def cleanup(self):
        fsa_list = self.fs_args.get('vbs_list')
        logger.info("Start to clear fsa on node%s" % fsa_list)
        itl_operate = InstallOperate(self.project_id, self.pod_id, self.fs_args)
        clear_fail_list = list()
        for fsa in fsa_list:
            fsa_ip = fsa.get('om_ip')
            ret_clr = itl_operate.clear_fsa(fsa_ip, fsa.get('user'), fsa.get('passwd'), fsa.get('root_pwd'))
            if ret_clr != 0:
                clear_fail_list.append(fsa_ip)
                logger.error("Failed to clean up FSA node[%s]. Please clean it by manually." % fsa_ip)
        if len(clear_fail_list) > 0:
            err_msg = "Failed to clean up nodes%s, Please clean it by manually" % clear_fail_list
            logger.error(err_msg)
            raise Exception(err_msg)
        return Message()

    def restore_factory(self):
        logger.info("Start to retore factory setting.")
        res_code = self.opr.first_login(DeployConstant.DM_LOGIN_USER, "", self.fs_args.get('dm_update_pwd'))
        if res_code != 0:
            err_msg = "Failed to login deploy manager"
            logger.error(err_msg)
            raise Exception(err_msg)

        res = self.opr.nodes_restore_factory()
        ret_code, ret_data = res.get_nodes_data()
        fail_nodes_list = ret_data.get('data').get('failed_nodes')
        success_nodes_list = ret_data.get('data').get('successful_nodes')
        if ret_code != 0 or len(fail_nodes_list) > 0:
            code = ret_data.get('result').get('code')
            err_des = ret_data.get('result').get('code')
            suggestion = ret_data.get('result').get('code')
            err_msg = "Failed to restore factory setting on nodes%s. Succeeful nodes%s. DetaiL:[%s]%s. Suggestion:%s." \
                      % (fail_nodes_list, success_nodes_list, code, err_des, suggestion)
            logger.error(err_msg)
            raise Exception(err_msg)
        logger.info("Succeed to retore factory setting%s." % success_nodes_list)
        self.opr.login_out(DeployConstant.DM_LOGIN_USER, self.fs_args.get('dm_update_pwd'))

    def reset_all_nodes(self):
        logger.info("Step1 restore factory setting all nodes")
        self.restore_factory()
