# coding=utf-8
import traceback

import utils.common.log as logger
from utils.common.message import Message
from utils.common.fic_base import TestCase
from utils.common.exception import HCCIException
from utils.common.fic_base import StepBaseInterface
from utils.DBAdapter.DBConnector import BaseOps
from utils.common.ssh_util import Ssh as SshUtil
from utils.business.project_condition_utils import get_project_condition_boolean
from plugins.DistributedStorage.logic.DeployOperate import FusionStorageOperate


class CheckPassword(TestCase):
    def __init__(self, project_id, pod_id):
        self.pod_id = pod_id
        self.project_id = project_id
        self.db = BaseOps()
        logger.error("project_id :%s pod_id：%s" % (project_id, pod_id))

    def procedure(self):
        """
        检查输入的密码是否正确，包括FSM admin和dsware的密码，所有节点的密码。
        扩AZ复用 TenantStorFBReuse80&(ExpansionAZ_KVM)
        扩计算节点 (TenantStorFBReuse80|TenantStorFB80)&(ExpansionComputeRes_KVMNode|ExpansionNetworkRes_NetworkNode)
        新增业务存储节点场景:ExpansionServiceStorage&TenantStorNewNode
        """
        if get_project_condition_boolean(self.project_id, 'TenantStorFBReuse80&ExpansionAZ_KVM'):
            logger.info("The type of project is : TenantStorFBReuse80&ExpansionAZ_KVM")
            # 1、检查业务存储的 dsware用户的密码
            expansion_az_fsm_float_ip = \
                self.db.get_user_input_cloud_param_by_key(self.project_id, "expansion_az_fsm_float_ip")
            reuse_fsm_dsware_passwd = \
                self.db.get_user_input_cloud_param_by_key(self.project_id, "reuse_fsm_dsware_passwd")
            if len(reuse_fsm_dsware_passwd) != 0:
                sshclient = SshUtil.ssh_create_client(expansion_az_fsm_float_ip, "dsware", reuse_fsm_dsware_passwd)
                SshUtil.ssh_close(sshclient)
            # 2、检查业务存储的 Portal的admin用户的密码
            reuse_fsm_admin_passwd = self.db.get_user_input_cloud_param_by_key(
                self.project_id, "reuse_fsm_admin_passwd")
            if len(reuse_fsm_admin_passwd) != 0:
                self.check_rest_password(expansion_az_fsm_float_ip, "admin", reuse_fsm_admin_passwd)

        if get_project_condition_boolean(
                self.project_id,
                '(TenantStorFB80|TenantStorFBHCI80)&(ExpansionComputeRes_KVMNode|ExpansionNetworkRes_NetworkNode)'):
            # 检查业务存储的 Portal的admin用户的密码
            reuse_fsm_admin_passwd = self.db.get_user_input_cloud_param_by_key(
                self.project_id, "reuse_fsm_admin_passwd")
            reuse_fsm_float_ip = self.db.get_user_input_cloud_param_by_key(
                self.project_id, "reuse_fsm_float_ip")
            self.check_rest_password(reuse_fsm_float_ip, "admin", reuse_fsm_admin_passwd)

        if get_project_condition_boolean(self.project_id, 'ExpansionServiceStorage&TenantStorNewNode'):
            # 检查原AZ存储节点root及普通用户密码格式、可登录性
            logger.info('Check the system account information format')
            original_az_osd_pwd_info = self.db.get_user_input_cloud_param_by_key(
                self.project_id, "original_az_storagenode_password")
            if not original_az_osd_pwd_info:
                err_msg = 'Failed to obtain original_az_storagenode_password'
                logger.error(err_msg)
                raise HCCIException(626260, 'original_az_storagenode_password')
            original_az_osd_pwd_info_list = original_az_osd_pwd_info.split(',')
            if len(original_az_osd_pwd_info_list) != 4:
                logger.error('The system account format is incorrect')
                raise HCCIException(626020, 'original_az_storagenode_password')
            if original_az_osd_pwd_info_list[0] != 'root':
                logger.error('The system account format is incorrect')
                raise HCCIException(626021, 'original_az_storagenode_password')

            reuse_fsm_admin_passwd = self.db.get_user_input_cloud_param_by_key(
                self.project_id, "reuse_fsm_admin_passwd")
            expansion_az_fsm_float_ip = self.db.get_user_input_cloud_param_by_key(
                self.project_id, "expansion_az_fsm_float_ip")
            ip_list = self.get_exist_pool_node_ip_list(expansion_az_fsm_float_ip, reuse_fsm_admin_passwd)
            logger.info("ip_list: %s" % ip_list)

            logger.info('Checking System Account Login')
            self.check_root_login(ip_list, original_az_osd_pwd_info)

        logger.info('Passed the check')

    @staticmethod
    def get_exist_pool_node_ip_list(expansion_az_fsm_float_ip, login_passwd):
        login_user = 'admin'
        operate = FusionStorageOperate(expansion_az_fsm_float_ip)
        status_code, error_code, error_des = operate.login(login_user, login_passwd)

        if status_code != 200 or error_code != 0:
            err_msg = "Failed to login deploy manager, Detail:[status:%s,code:%s]%s" % (
                status_code, error_code, error_des)
            logger.error(err_msg)
            raise Exception(traceback.format_exc())

        logger.info("Query storage pool data.")
        res_pool = operate.query_storage_pool()
        pool_info = res_pool.get_query_data()
        if len(pool_info.get('storagePools')) == 0:
            logger.error('check pool fail,  pool info:{}'.format(pool_info))
            raise Exception("check pool fail")

        pool_id_list = [str(pool.get('poolId')) for pool in pool_info.get('storagePools')]
        logger.info("Get storage pool list%s." % pool_id_list)

        storage_node_ip_list = list()
        for pool_id in pool_id_list:
            rsp_data = operate.query_storage_node_by_pool_id(pool_id)
            pool_data = rsp_data.get_query_data()
            node_data_list = pool_data.get('nodeInfo')
            node_mgr_ip_list = [node.get('nodeMgrIp') for node in node_data_list]
            storage_node_ip_list += node_mgr_ip_list
        logger.info("Get storage node ip list[%s] from pool list%s." % (storage_node_ip_list, pool_id_list))

        operate.login_out(login_user, login_passwd)
        return storage_node_ip_list

    @staticmethod
    def check_root_login(ip_list, user_password):
        """
        检查LLD表填写的原AZ存储节点账号登录信息的可登录性： original_az_storagenode_password
        """
        logger.info("begin to check root and common user can log in")
        user_password_list = user_password.split(",")
        success_login_node = []
        for ip_info in ip_list:
            try:
                client = SshUtil.ssh_create_client(ip_info, user_password_list[2], user_password_list[3])
            except Exception:
                logger.error('create ssh client failed, node ip:{}'.format(ip_info))
                continue
            logger.info('login common user success, ip:{}'.format(ip_info))
            try:
                SshUtil.ssh_send_command(client, 'su', 'Password', 10)
                SshUtil.ssh_send_command(client, user_password_list[1], '#', 10)
            except Exception:
                logger.error('Failed to switch to the root, node ip:{}'.format(ip_info))
                continue
            SshUtil.ssh_close(client)
            success_login_node.append(ip_info)
        if not success_login_node:
            err_msg = 'login failure, nodes:{}'.format(ip_list)
            raise HCCIException(626309, err_msg)
        logger.info('Logged in to the node as the root user, nodes:{}'.format(success_login_node))

    @staticmethod
    def check_rest_password(address, login_user, login_passwd):
        try:
            operate = FusionStorageOperate(address)
            status_code, error_code, error_des = operate.login(login_user, login_passwd)
            if status_code != 200 or error_code != 0:
                err_msg = "Failed to login rest, Detail:[status:%s,code:%s]%s" % (
                    status_code, error_code, error_des)
                logger.error(err_msg)
                raise Exception(err_msg)
        except HCCIException as fcd_e:
            err_msg = "Failed to login rest [%s]：%s" % (address, str(fcd_e))
            logger.error(err_msg)
            raise fcd_e
        except Exception as e:
            err_msg = "Failed to login rest [%s]：%s" % (address, e)
            logger.error(err_msg)
            raise Exception(err_msg)

    def failure(self):
        super(CheckPassword, self).failure()


class CheckPasswordInterface(StepBaseInterface):
    def __init__(self, project_id, pod_id):
        super(CheckPasswordInterface, self).__init__(project_id, pod_id)
        self.project_id = project_id
        self.pod_id = pod_id
        self.implement = CheckPassword(project_id, pod_id)

    def pre_check(self, project_id, pod_id):
        """
        插件内部接口：执行安装前的资源预检查，该接口由execute接口调用，工具框架不会直接调用此接口。
        :param project_id:
        :param pod_id:
        :return:Message类对象
        """
        return Message(200)

    def execute(self, project_id, pod_id):
        try:
            self.implement.procedure()
            return Message(200)
        except HCCIException as e1:
            return Message(500, e1)
        except Exception as e2:
            return Message(500, HCCIException('90034', str(e2)))

    def rollback(self, project_id, pod_id):
        """
        标准调用接口：执行回滚
        :param project_id:
        :param pod_id:
        :return:Message类对象
        """
        return Message(200)

    def retry(self, project_id, pod_id):
        """
        标准调用接口：重试
        :return: Message类对象
        """
        return self.execute(project_id, pod_id)

    def check(self, project_id, pod_id):
        """
        标准调用接口：重试
        :param project_id:
        :param pod_id:
        :return:Message类对象
        """
        return Message(200)
