# -*- coding: utf-8 -*-
import traceback
import requests
import os
import utils.common.log as logger
from utils.common.exception import FCUException
from utils.common.ssh_util import Ssh
from utils.common.param_check import check_param_ip
from platforms.param.param_check_handler import HandleParamCheck
from platforms.param.param_service import ParamService
from utils.DBAdapter.DBConnector import BaseOps
from plugins.eBackup.common.util import get_cascaded_reverse_ips, get_eBackup_Driver_nodes, ping_reverse_proxy_ips
from plugins.eBackup.common.util import Utils
from utils.business.project_util import ProjectApi


def params_check(project_id):
    """
    插件参数校验接口函数
    错误信息返回值（需要中英文信息）：
        1、支持通过FCUException(error_code, *arg, **kwargs)类获取中英文信息,此方法是获取公共方法中的错误
        2、支持通过code2Msg(error_code, *arg, **kwargs)函数获取中英文信息,此方法是获取各组件自定义的错误
    """
    db_opt = ParamService()
    check_data = db_opt.get_need_check_cloud_params(project_id, "eBackup")
    check_data.update(db_opt.get_need_check_cloud_params(project_id, "OpenStack"))
    check_data.update({"eBackup_Workflow_nodes": check_data['eBackup_Workflow_nodes'].replace(",", ";")})
    check_data.update({"eBackup_Datamover_nodes": check_data['eBackup_Datamover_nodes'].replace(",", ";")})
    check_data.update({"current_region_id": ProjectApi().get_regionlist_by_project_Id(project_id)[0]})
    check_result = HandleParamCheck()
    all_params = ["openstack_cps_web_pwd", "openstack_cps_admin_pwd",
                  "eBackup_Workflow_nodes", "eBackup_Datamover_nodes", "eBackup_hcp_pwd",
                  "eBackup_root_pwd", "eBackup_admin_pwd"]

    is_true = check_is_empty(check_data, check_result, all_params)
    if not is_true:
        return check_result
    is_true = is_exist_same_ips(check_result, "eBackup_Datamover_nodes", check_data.get("eBackup_Datamover_nodes"))
    is_true = is_true and is_exist_same_ips(check_result, "eBackup_Workflow_nodes", check_data.get("eBackup_Workflow_nodes") )
    if not is_true:
        return check_result

    unpassed_eBackup_hcp_nodes = []
    unpassed_eBackup_root_nodes = []
    unpassed_openstack_fsp_nodes = []
    unpassed_openstack_root_nodes = []

    check_eBackup_nodes(check_result,"eBackup_Datamover_nodes",check_data.get("eBackup_Datamover_nodes"),
                        check_data.get("eBackup_hcp_pwd"),check_data.get("eBackup_root_pwd"),
                        unpassed_eBackup_hcp_nodes,unpassed_eBackup_root_nodes)
    check_eBackup_nodes(check_result,"eBackup_Workflow_nodes",check_data.get("eBackup_Workflow_nodes"),
                        check_data.get("eBackup_hcp_pwd"),check_data.get("eBackup_root_pwd"),
                        unpassed_eBackup_hcp_nodes,unpassed_eBackup_root_nodes)
    if 0 == len(unpassed_eBackup_hcp_nodes):
        check_result.set_check_result(param_keys=["eBackup_hcp_pwd"], status=200, error_msg="")
    else:
        check_result.set_check_result(param_keys=["eBackup_hcp_pwd"], status=500, error_msg=FCUException(650001, ",".join(unpassed_eBackup_hcp_nodes)))

    if 0 == len(unpassed_eBackup_root_nodes):
        check_result.set_check_result(param_keys=["eBackup_root_pwd"], status=200, error_msg="")
    else:
        check_result.set_check_result(param_keys=["eBackup_root_pwd"], status=500, error_msg=FCUException(650002,",".join(unpassed_eBackup_root_nodes)))

    check_openstack_params(check_result,project_id,check_data,unpassed_openstack_fsp_nodes,unpassed_openstack_root_nodes)
    if 0 != len(unpassed_openstack_fsp_nodes):
        check_result.set_check_result(param_keys=["openstack_cps_admin_pwd"], status=500,
                                      error_msg=FCUException(650005, ",".join(unpassed_openstack_fsp_nodes)))
    if 0 != len(unpassed_openstack_root_nodes):
        check_result.set_check_result(param_keys=["openstack_cps_admin_pwd"], status=500,
                                      error_msg=FCUException(650006, ",".join(unpassed_openstack_root_nodes)))

    # check workflow web login
    hcp_password = check_data.get("eBackup_hcp_pwd")
    root_password = check_data.get("eBackup_root_pwd")
    admin_password = check_data.get("eBackup_admin_pwd")
    workflow_hosts = check_data.get("eBackup_Workflow_nodes").split(";")
    is_true = check_web_login(check_result, workflow_hosts, hcp_password, root_password, admin_password, 2)
    if is_true:
        b_result = is_in_same_cluster(check_result, 'eBackup_Workflow_nodes', workflow_hosts, hcp_password, root_password, admin_password, 2)
        if b_result:
            check_ebackup_role(check_result, 'eBackup_Workflow_nodes', workflow_hosts, hcp_password, root_password)
    if is_true:
        for datamover_groups in check_data.get("eBackup_Datamover_nodes").split("|"):
            datamover_hosts = datamover_groups.split(";")
            is_true = check_web_login(check_result, datamover_hosts, hcp_password, root_password, admin_password, 1)
            if is_true:
                b_result = is_in_same_cluster(check_result, 'eBackup_Datamover_nodes', datamover_hosts, hcp_password, root_password, admin_password, 1)
                if b_result:
                    b_result = check_ebackup_role(check_result, 'eBackup_Datamover_nodes', datamover_hosts, hcp_password, root_password)
                    if not b_result:
                        break
                else:
                    break
            else:
                break

    enable_other_params(check_result, all_params)

    return check_result


def enable_other_params(check_result, all_params):
    for each in all_params:
        if -1 == str(check_result.check_list).find(each):
            check_result.set_check_result(param_keys=[each], status=200, error_msg="")

def check_ssh_login(server_ip, account, account_passwd, account_root_passwd):
    ssh_client = None
    try:
        ssh_client = Ssh.ssh_create_client(server_ip, account, account_passwd)
        Ssh.ssh_send_command(ssh_client, 'su - root', 'Password:', 100)
        Ssh.ssh_send_command(ssh_client, account_root_passwd, '#', 100)
        return True, ""
    except Exception as e:
        if not ssh_client:
            logger.error("Ssh login {0} as {1} user failed.The reason is:{2}".format(server_ip, account, str(e)))
            return False, account
        else:
            logger.error("su - root on {0} failed.The reason is {1}".format(server_ip, str(e)))
            return False, 'root'
    finally:
        Utils.close_ssh_clinet(ssh_client)


def check_eBackup_nodes(check_result,params_key,nodes,account_passwd,account_root_passwd,unpassed_ordinary_user_nodes,unpassed_root_nodes):
    flag = True
    ip_list = nodes.replace(" ", "").replace("|", ";").split(";")

    for ip in ip_list:
        try:
            ret = check_param_ip(ip)
            if not ret:
                flag = False
                check_result.set_check_result(param_keys=[params_key],status=500, error_msg=FCUException(650034))
        except FCUException as error:
            check_result.set_check_result(param_keys=[params_key],status=500, error_msg=error)
    if flag:
        check_result.set_check_result(param_keys=[params_key],status=200, error_msg="")
        for ip in ip_list:
            is_true, account = check_ssh_login(ip,"hcp",account_passwd,account_root_passwd)
            if not is_true:
                flag = False
                if "root" == account:
                    unpassed_root_nodes.append(ip)
                else:
                    unpassed_ordinary_user_nodes.append(ip)
    return flag


def check_openstack_params(check_result,project_id,param_dict,unpassed_openstack_fsp_nodes,unpassed_openstack_root_nodes):
    database = BaseOps()
    region_type = database.get_region_type(project_id)
    reverse_proxy_ip = param_dict["openstack_reverse_proxy_ip"]

    if region_type.lower() == "type1":
        try:
            cascaded_reverse_ips = get_cascaded_reverse_ips(param_dict)
            if 0 == len(cascaded_reverse_ips):
                check_result.set_check_result(param_keys=["openstack_cps_web_pwd"], status=500,
                                              error_msg=FCUException(650016, reverse_proxy_ip))
                return False
            else:
                is_true = ping_reverse_proxy_ips(check_result, "openstack_cps_web_pwd", cascaded_reverse_ips, 
                                                 reverse_proxy_ip, param_dict["current_region_id"])
                if is_true:
                    check_result.set_check_result(param_keys=["openstack_cps_web_pwd"], status=200, error_msg="")
                else:
                    return False
        except Exception as ex:
            check_result.set_check_result(param_keys=["openstack_cps_web_pwd"], status=500,
                                          error_msg=FCUException(650008,str(ex)))
            return False

        for each_reverse_ip in cascaded_reverse_ips:
            is_true, account = check_ssh_login(each_reverse_ip,"fsp",param_dict["openstack_fsp_pwd"],param_dict["openstack_root_pwd"])
            if not is_true:
                if "root" == account:
                    unpassed_openstack_root_nodes.append(each_reverse_ip)
                else:
                    unpassed_openstack_fsp_nodes.append(each_reverse_ip)
                continue
            try:
                driver_host_dict = get_eBackup_Driver_nodes(each_reverse_ip,param_dict)
                if 0 == len(driver_host_dict):
                    continue
                driver_nodes = driver_host_dict["eBackupDriver"] + driver_host_dict["cpsnode"]
                for node in driver_nodes:
                    result, account = check_ssh_login(node,"fsp",param_dict["openstack_fsp_pwd"],param_dict["openstack_root_pwd"])
                    if not result:
                        if "root" == account:
                            unpassed_openstack_root_nodes.append(node)
                        else:
                            unpassed_openstack_fsp_nodes.append(node)
                check_result.set_check_result(param_keys=["openstack_cps_admin_pwd"], status=200, error_msg="")
            except Exception as ex:
                check_result.set_check_result(param_keys=["openstack_cps_admin_pwd"], status=500, error_msg=FCUException(650008,str(ex)))
    else:
        check_result.set_check_result(param_keys=["openstack_cps_web_pwd"], status=200, error_msg="")
        is_true, account = check_ssh_login(reverse_proxy_ip,"fsp",param_dict["openstack_fsp_pwd"],param_dict["openstack_root_pwd"])
        if not is_true:
            if "root" == account:
                unpassed_openstack_root_nodes.append(reverse_proxy_ip)
            else:
                unpassed_openstack_fsp_nodes.append(reverse_proxy_ip)
            return False
        try:
            driver_host_dict = get_eBackup_Driver_nodes(reverse_proxy_ip, param_dict)
            driver_nodes = driver_host_dict["eBackupDriver"] + driver_host_dict["cpsnode"]
            for node in driver_nodes:
                result,account = check_ssh_login(node,"fsp",param_dict["openstack_fsp_pwd"],param_dict["openstack_root_pwd"])
                if not result:
                    if "root" == account:
                        unpassed_openstack_root_nodes.append(node)
                    else:
                        unpassed_openstack_fsp_nodes.append(node)
            check_result.set_check_result(param_keys=["openstack_cps_admin_pwd"], status=200, error_msg="")
        except Exception as ex:
            check_result.set_check_result(param_keys=["openstack_cps_admin_pwd"], status=500, error_msg=FCUException(650008,str(ex)))


def check_web_login(check_result, hosts_groups, hcp_password, root_password, admin_password, role):
    web_ip = Utils.find_float_ip(hosts_groups, hcp_password, root_password)
    if web_ip == "":
        check_result.set_check_result(param_keys=["eBackup_admin_pwd"], status=500, error_msg=FCUException(650017, str(hosts_groups)))
        return False

    ip_version = Utils.check_ip_version(web_ip)
    token = ""
    session = ""
    try:
        token, session = Utils.login(web_ip, admin_password, ip_version)
        check_result.set_check_result(param_keys=["eBackup_admin_pwd"], status=200,
                                      error_msg="")
        return True
    except FCUException as e:
        check_result.set_check_result(param_keys=["eBackup_admin_pwd"], status=500, error_msg=e)
        return False
    except Exception as e:
        check_result.set_check_result(param_keys=["eBackup_admin_pwd"], status=500, error_msg=FCUException(650008, str(e)))
        return False
    finally:
        Utils.logout(web_ip, token, session, role, ip_version)


def check_is_empty(params_dict, check_result, params_key_list):
    ret = True
    for key in params_key_list:
        if params_dict[key] is None or 0 == len(params_dict[key]):
            ret = False
            check_result.set_check_result(param_keys=[key], status=500, error_msg=FCUException(650035))
    return ret


def is_exist_same_ips(check_result, key, host_ips):
    ip_list = []
    all_ip_list = host_ips.replace("|", ";").split(";")
    for ip in all_ip_list:
        if ip not in ip_list:
            ip_list.append(ip)
        else:
            check_result.set_check_result(param_keys=[key], status=500, error_msg=FCUException(650010))
            return False
    return True


def is_in_same_cluster(check_result, key, host_ips_list, hcp_password, root_password, admin_password, role):
    token = ""
    session = ""
    try:
        logger.info("Begin to check if the hosts %s are in the same cluster." % str(host_ips_list))
        web_ip = Utils.find_float_ip(host_ips_list, hcp_password, root_password)
        if 0 == len(web_ip):
            logger.error("Find float failed.")
            raise Exception("Find float failed.")
        ip_version = Utils.check_ip_version(web_ip)
        if ip_version == 4:
            url = "https://%s:8088/rest/dev/vbackup_server" % web_ip
        else:
            url = "https://[%s]:8088/rest/dev/vbackup_server" % web_ip
        token, session = Utils.login(web_ip, admin_password, ip_version)
        header = {
                'Accept': 'application/json;version=2.2;charset=UTF-8',
                'iBaseToken': token,
                'Accept-Language': 'en',
                'Cookie': 'language=en; %s;DEVICE_ID=dev;sessionIdleTime=60000;MACHINEROLE=%s;CSRF_IBASE_TOKEN=%s' % (session, role, token)}
        rsp = requests.get(url=url, headers=header, verify=False)
        if rsp.status_code == 200:
            rsp_dict = rsp.json()
            error_code = rsp_dict["error"]["code"]
            if error_code is None:
                logger.error("errcode is empty.")
                raise Exception("errcode is empty.")
            if error_code != 0:
                logger.error("Query alarm info failed on [%s],the description is:%s"
                             % (web_ip, rsp_dict["error"]["description"]))
                raise Exception(rsp_dict["error"]["description"])

            all_host = []
            for host in rsp_dict["data"]:
                if host["MANAGEMENTIP"] not in all_host:
                    all_host.append(host["MANAGEMENTIP"])
            logger.info("The host ips by user inputing are:" + str(host_ips_list))
            logger.info("The host ips by querying are:" + str(all_host))

            if len(host_ips_list) == len(all_host):
                is_true = True
                for ip in host_ips_list:
                    if ip not in all_host:
                        is_true = False
                        break
                if is_true:
                    check_result.set_check_result(param_keys=[key], status=200, error_msg="")
                    return True

            check_result.set_check_result(param_keys=[key], status=500, error_msg=FCUException(650020, ';'.join(host_ips_list), ';'.join(all_host), key))
            return False
        else:
            logger.error("Response status code is not 200.The url is" + url)
            raise Exception("Response status code is not 200.")
    except Exception as e:
        logger.error("Exception occurs:" + str(e))
        check_result.set_check_result(param_keys=[key], status=500, error_msg=FCUException(650008, str(e)))
        return False
    finally:
        Utils.logout(web_ip, token, session, role, ip_version)


def check_ebackup_role(check_result, key, host_ips_list, hcp_password, root_password):
    try:
        ssh_clinet = None
        roles = []
        unpassed_ips = []
        if key == 'eBackup_Workflow_nodes':
            roles = ['2', '3']
        elif key == 'eBackup_Datamover_nodes':
            roles = ['0', '1']
        else:
            logger.error("key {} is invalid.".format(key))
            raise FCUException(650008, "key {} is invalid.".format(key))
        query_role_cmd = '''cat /opt/huawei-data-protection/ebackup/conf/hcpconf.ini | grep MachineRole |awk -F "=" '{print int($2)}' '''
        for ip in host_ips_list:
            try:
                ssh_client = Ssh.ssh_create_client(ip, 'hcp', hcp_password)
                Ssh.ssh_send_command(ssh_client, 'su - root', 'Password:', 100)
                Ssh.ssh_send_command(ssh_client, root_password, '#', 100)
                result = Ssh.ssh_exec_command_return_list(ssh_client, query_role_cmd)
                logger.info("The server role is {0} of host {1}".format(str(result[0]), ip))
                role = result[0].strip().replace('\n', '')
                if role not in roles:
                    logger.error("The node[{0}] is not a {1} node".format(ip, key))
                    unpassed_ips.append(ip)
            except Exception as e:
                logger.error("Exception occurs: " + str(e))
                raise e
            finally:
                Ssh.ssh_close(ssh_client)
        if 0 != len(unpassed_ips):
            logger.error('These nodes {0} are not {1} role node.'.format(str(host_ips_list), key) )
            check_result.set_check_result(param_keys=[key], status=500, error_msg=FCUException(650023, ';'.join(host_ips_list), key, key))
            return False
        else:
            check_result.set_check_result(param_keys=[key], status=200, error_msg="")
            return True
    except Exception as e:
        check_result.set_check_result(param_keys=[key], status=500, error_msg=FCUException(650008, str(e)))
        return False



		
