# -*- coding:utf-8 -*-
import utils.common.log as logger
from utils.client.webUI_client import g_webui_client_ctrl
from utils.common.ssh_util import Ssh
from platforms.upgradecheck.check_result import CheckResult
from utils.common.exception import FCUException
from utils.business.param_util import ParamUtil
from utils.business.service_monitor.service_monitor import ServiceNodeCfg, ServiceMonitorCfg, set_service_m_cfg
from IPy import IP
import json
import requests
import time
import subprocess
import os
from utils.Logic.ServerOperate import ServerOperate

import base64


g_check_item = {
    "cpu_health":            {"name_cn": "CPU健康度",    "name_en": "CPU Health",           "error_code": '650026'},
    "disk_health":           {"name_cn": "硬盘健康度",   "name_en": "Disk Health",          "error_code": '650027'},
    "disk_space":            {"name_cn": "硬盘空闲空间", "name_en": "Free Disk Space",      "error_code": '650003'},
    "network_health":        {"name_cn": "网络健康度",   "name_en": "Network Health",       "error_code": '650028'},
    "service_health":        {"name_cn": "服务健康度",   "name_en": "Service Health",       "error_code": '650004'},
    "ha_health":             {"name_cn": "HA健康度",     "name_en": "HA Health",            "error_code": '650029'},
    "micro_service_health":  {"name_cn": "微服务健康度", "name_en": "Micro Service Health", "error_code": '650030'},
    "version_compatibility": {"name_cn": "兼容性",       "name_en": "Micro Service Health", "error_code": '650019'},
    "alarm_reporting":       {"name_cn": "对接OC告警",   "name_en": "Connect OC alarm",     "error_code": '650031'},
    "access_status":         {"name_cn": "可访问状态",   "name_en": "Accessibility Status", "error_code": '650033'}
}


def get_reverse_proxy_file(current_region_id, reverse_proxy_ip):
    return os.path.abspath(__file__ + '/../' + current_region_id + '_' + reverse_proxy_ip + '_cascaded_ips.txt')


def open_file_util(file_name, mode='r', encoding=None, **kwargs):
    if mode in ['r', 'rt', 'tr'] and encoding is None:
        with open(file_name, 'rb') as f:
            context = f.read()
            for encoding_item in ['UTF-8', 'GBK', 'ISO-8859-1']:
                try:
                    context.decode(encoding=encoding_item)
                    encoding = encoding_item
                    break
                except UnicodeDecodeError as e:
                    pass
    return open(file_name, mode=mode, encoding=encoding, **kwargs)


class Utils(object):
    @staticmethod
    def get_config_content(file_path):
        file_object = open_file_util(file_path)
        content = ""
        try:
            for line in file_object:
                content = "{0}{1}".format(content, line)
        except Exception as msg:
            errmsg = 'format content is failed, message is "%s"' % msg
            logger.error(errmsg)
            raise errmsg
        finally:
            file_object.close()
        return content

    @staticmethod
    def close_ssh_clinet(ssh_client):
        try:
            Ssh().ssh_close(ssh_client)
        except Exception as e:
            logger.info("Close ssh client failed,the reason is %s" % str(e))

    @staticmethod
    def find_float_ip(host_list, hcp_password, root_password):
        try:
            ssh = Ssh()
            find_float_ip_cmd = 'cat /opt/huawei-data-protection/ebackup/conf/floatIpBak || echo "isSignleMode"'
            float_ip = ""
            result = None
            for ip in host_list:
                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, find_float_ip_cmd)
                Utils.close_ssh_clinet(ssh_client)
                logger.info("The result is %s." % str(result))
                if -1 != str(result).find("isSignleMode"):
                    logger.info("It is in SignleMode or this node is a proxy node.")
                    continue
                float_ip = result[0].strip().replace("\n", "")
                if float_ip != "":
                    logger.info("The float ip of host(%s) is %s." % (str(host_list), float_ip))
                    return float_ip

            if -1 != str(result).find("isSignleMode"):
                logger.info("It is in SignleMode,use admin node ip as float ip.")
                float_ip = Utils.find_admin_ip(host_list, hcp_password, root_password)
                if float_ip != "":
                    logger.info("It is in SignleMode,The admin node ip is %s." % float_ip)
                    return float_ip
            logger.error("Find float ip of host(%s) failed." % str(host_list))
            return float_ip
        except Exception as e:
            logger.info("Find float ip failed,the reason is %s" % str(e))
            return ""

    @staticmethod
    def find_admin_ip(host_list, hcp_password, root_password):
        try:
            ssh = Ssh()
            is_admin_node = 'ps -ef | grep -v "grep" | grep "AdminNode" >/dev/null 2>&1 && echo "isAdminNode"'
            ret = ""
            for ip in host_list:
                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 = str(ssh.ssh_exec_command_return(ssh_client, is_admin_node))
                Utils.close_ssh_clinet(ssh_client)
                if -1 != result.find("isAdminNode"):
                    ret = str(ip)
                    logger.info("The admin node of hosts(%s) is %s" % (str(host_list), ip))
                    return ret
            logger.info("Find admin node of host(%s) failed." % str(host_list))
            return ret
        except Exception as e:
            logger.info("Find admin node ip failed,the reason is %s" % str(e))
            return ""

    @staticmethod
    def login(web_ip, password, ip_version=4, user="admin", scope=0):
        try:
            if ip_version == 4:
                url = 'https://%s:8088/rest/dev/login' % web_ip
            else:
                url = 'https://[%s]:8088/rest/dev/login' % web_ip
            header = {'Accept': 'application/json', 'Accept-Language': 'en'}
            data = '{"scope":%s,"username":"%s","password":"%s"}' % (scope, user, password)

            logger.info("Begin to login ebackup(%s)" % str(web_ip))
            rsp = requests.post(url, headers=header, data=data, 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 FCUException(650009, web_ip)
                if error_code != 0:
                    logger.error("Login %s failed,the description is:%s"
                                 % (web_ip, rsp_dict["error"]["description"]))
                    raise FCUException(650009, web_ip)
                account_state = rsp_dict["data"]["accountstate"]
                if account_state == 3:
                    logger.error("Login %s failed,description:the account password is expired!")
                    raise FCUException(650025, web_ip)
                token = json.loads(rsp.text)["data"]["iBaseToken"]
                session = rsp.headers.get('Set-Cookie').split(';')[0]
            else:
                logger.error("Request status code is %s,login %s failed"
                             % (str(rsp.status_code), web_ip))
                raise Exception("Login %s failed.Request Request status code is %s"
                                % (web_ip, str(rsp.status_code)))
            logger.info("Login %s successfully." % web_ip)
            return token, session
        except Exception as e:
            logger.info("Login %s failed." % web_ip)
            raise e

    @staticmethod
    def logout(web_ip, token, session, role, ip_version=4):
        try:
            if token == "" and session == "":
                return True

            if ip_version == 4:
                url = "https://%s:8088/rest/dev/sessions" % web_ip
            else:
                url = "https://[%s]:8088/rest/dev/sessions" % web_ip
            header = {'Accept': 'application/json;version=2.2;charset=UTF-8', 'iBaseToken': token,
                       'Cookie': 'language=en; %s; DEVICE_ID=dev;'
                                 'sessionIdleTime=60000; MACHINEROLE=%s;'
                                 'CSRF_IBASE_TOKEN=%s' % (session, role, token)}

            rsp = requests.delete(url, headers=header, verify=False)
            if rsp.status_code != 200:
                logger.error("Logout %s failed." % web_ip)
                return False
            logger.info("Logout %s successfully." % web_ip)
            return True
        except Exception as e:
            logger.error("Logout %s failed.The reason is %s" % (web_ip, str(e)))
            return False

    @staticmethod
    def login_governance(base_url, password, ssh, ssh_client):
        try:
            url = '%s/v3/auth/tokens' % base_url
            login_data = ''' '{"auth": {"identity" : {"methods" : ["password"],"password" : {"user" : ''' + \
                         '''{"name" : "admin","password" : "%s","iam_type" : 0}}}}}' ''' % password
            header = '"Accept:application/json"'
            get_token_cmd = 'export LD_LIBRARY_PATH=/opt/huawei-data-protection/ebackup/libs && ' \
                            '/opt/huawei-data-protection/ebackup/sbin/SecurityTool dmk post %s %s %s 2>/dev/null' \
                            % (url, login_data, header)
            result = ssh.ssh_exec_command_return(ssh_client, get_token_cmd)
            if -1 != str(result).find("ResponseCode OK"):
                try:
                    rsp_dict = {}
                    for index, val in enumerate(result):
                        if -1 != str(val).find("Data"):
                            rsp_dict = json.loads(result[index].replace('\n', ''))
                            break
                    if not rsp_dict:
                        logger.error("There is no token in response result,the response is " + str(result))
                        raise Exception("There is no token in response result,the response is " + str(result))
                    if rsp_dict["Error"]["Code"] != 0:
                        logger.error("Get token failed,the error code is" + rsp_dict["Error"]["Code"])
                        raise Exception("Get token failed,the error code is" + rsp_dict["Error"]["Code"])
                    token = rsp_dict["Data"]["token"]
                    return token
                except Exception as e:
                    logger.error("Get token failed,the result is" + str(result))
                    logger.error("The exception is: " + str(e))
                    raise Exception("Convert result to dict failed.")
            else:
                logger.error("Response Code is not 200")
                raise Exception("Response Code is not 200")
        except Exception as e:
            raise e

    @staticmethod
    def logout_governance(base_url, token, ssh, ssh_client):
        try:
            if token is None or token == "" or not ssh_client:
                return True

            url = "%s/v3/auth/tokens" % base_url
            security_tool = '/opt/huawei-data-protection/ebackup/sbin/SecurityTool'
            logout_cmd = '%s dmk delete %s "" "X-Auth-Token:%s" 2>/dev/null' % (security_tool, url, token)
            result = ssh.ssh_exec_command_return(ssh_client, logout_cmd)
            if -1 != str(result).find("ResponseCode OK"):
                try:
                    rsp_dict = {}
                    for index, val in enumerate(result):
                        if -1 != str(val).find("Data"):
                            rsp_dict = json.loads(result[index].replace('\n', ''))
                            break
                    if rsp_dict["Error"]["Code"] != 0:
                        logger.error("Logout %s failed" % base_url)
                        return False
                except Exception as e:
                    logger.error("Logout %s failed,the reason is:%s" % (base_url, str(e)))
                    return False
            else:
                logger.error("Response Code not 200")
                return False
            logger.info("Logout governance %s successfully" % base_url)
            return True
        except Exception as e:
            logger.error("Logout governace failed,the reason is: " + str(e))
            return False

    @staticmethod
    def check_ip_version(ip):
        try:
            m_ip = IP(ip)
            return m_ip.version()
        except Exception as e:
            logger.error("%s is not a valid ip address.The reason is %s" % (ip, str(e)))
            return -1

    @staticmethod
    def init_system_params(project_id, region_id):
        try:
            util = ParamUtil()
            params_dict = util.get_service_cloud_param(project_id, "eBackup", region_id)
            commom_params = {
                "dmk_floatIp": util.get_value_from_cloud_param(
                    project_id, "DMK_public_params", "dmk_floatIp", region_id),
                "dmk_os_business_username": util.get_value_from_cloud_param(
                    project_id, "DMK_public_params", "dmk_os_business_username", region_id),
                "dmk_os_business_user_password": util.get_value_from_cloud_param(
                    project_id, "DMK_public_params", "dmk_os_business_user_password", region_id),
                "dmk_ui_username": util.get_value_from_cloud_param(
                    project_id, "DMK_public_params", "dmk_ui_username", region_id),
                "dmk_ui_password": util.get_value_from_cloud_param(
                    project_id, "DMK_public_params", "dmk_ui_password", region_id),
                "openstack_reverse_proxy_ip": util.get_value_from_cloud_param(
                    project_id, 'OpenStack', 'openstack_reverse_proxy_ip', region_id),
                "openstack_fsp_pwd": util.get_value_from_cloud_param(
                    project_id, 'OpenStack', 'openstack_fsp_pwd', region_id),
                "openstack_root_pwd": util.get_value_from_cloud_param(
                    project_id, 'OpenStack', 'openstack_root_pwd', region_id),
                "openstack_external_api_cps_web_port": util.get_value_from_cloud_param(
                    project_id, 'OpenStack', 'openstack_external_api_cps_web_port', region_id),
                "openstack_cloud_admin_pwd": util.get_value_from_cloud_param(
                    project_id, 'OpenStack', 'openstack_cloud_admin_pwd', region_id),
                "openstack_region": util.get_value_from_cloud_param(
                    project_id, 'OpenStack', 'openstack_region', region_id),
                "keystoneurl": util.get_value_from_cloud_param(
                    project_id, 'OpenStack', 'keystoneurl', region_id),
                "mo_tenant_float_ip": util.get_value_from_cloud_param(
                    project_id, 'ManageOne_public_params', 'ManageOne_moTenantFloatIp', region_id),
                "mo_web_port": util.get_value_from_cloud_param(
                    project_id, 'ManageOne_public_params', 'ManageOne_webPort', region_id),
                "current_region_id": region_id
            }
            params_dict.update(commom_params)
            params_dict.update({"eBackup_Workflow_nodes": params_dict["eBackup_Workflow_nodes"].replace(",", ";").lower()})
            params_dict.update({"eBackup_Datamover_nodes": params_dict["eBackup_Datamover_nodes"].replace(",", ";").lower()})
            logger.info("Init eBackup system parameters successfully.")
            if params_dict['update_scene'] == 'patch':
                from plugins.eBackup.common.get_patch_info import get_patch_info
                patch_info = get_patch_info(project_id)
                params_dict.update({'eBackup_Version': patch_info[0]['UpdateInfo_en']['Version']['value']})
            return params_dict
        except Exception as e:
            logger.error("Init eBackup system parameters failed.the reason is " + str(e))
            raise e

    @staticmethod
    def query_openstack_info(float_ip, password):
        token = ""
        session = ""
        try:
            ret_dict = {}
            logger.info("Begin to query openstack info at host:[%s]" % float_ip)
            ip_version = Utils.check_ip_version(float_ip)
            if ip_version == 4:
                url = "https://%s:8088/rest/dev/openstack_settings/default" % float_ip
            else:
                url = "https://[%s]:8088/rest/dev/openstack_settings/default" % float_ip

            token, session = Utils.login(float_ip, 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=2;CSRF_IBASE_TOKEN=%s' % (session, 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 openstack info failed on [%s],the description is:%s"
                                 % (float_ip, rsp_dict["error"]["description"]))
                    raise Exception(rsp_dict["error"]["description"])
                ret_dict = rsp_dict["data"]
            else:
                logger.error("Response status code is not 200.The url is" + url)
                raise Exception("Response status code is not 200.")

            logger.info("Query openstack info successfully.")
            logger.info("IAM:" + ret_dict["AUTHURL"])
            logger.info("Nova:" + ret_dict["NOVAURL"])
            logger.info("Cinder:" + ret_dict["CINDERURL"])
            logger.info("Neutron:" + ret_dict["NEUTRONURL"])
            return ret_dict
        except Exception as e:
            logger.error("Query openstack info failed.The reason is: " + str(e))
            return {}
        finally:
            Utils.logout(float_ip, token, session, 2)

    @staticmethod
    def query_alarm_info(float_ip, password):
        token = None
        session = None

        try:
            logger.info("Begin to query alarm info.")
            manageone_oc_base_url = ''
            ip_version = Utils.check_ip_version(float_ip)
            if ip_version == 4:
                url = "https://%s:8088/rest/dev/alarm_settings/default" % float_ip
            else:
                url = "https://[%s]:8088/rest/dev/alarm_settings/default" % float_ip

            token, session = Utils.login(float_ip, 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=2;CSRF_IBASE_TOKEN=%s' % (session, 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"
                                 % (float_ip, rsp_dict["error"]["description"]))
                    raise Exception(rsp_dict["error"]["description"])
                if "ALARMSERVERURL" not in rsp_dict["data"] or 0 == len(rsp_dict["data"]["ALARMSERVERURL"]):
                    logger.error("Alarm report is not configured.")
                    raise Exception("Alarm report is not configured.")
                if rsp_dict["data"]["ISALARMON"] != '1':
                    logger.error("Alarm report is not enable.")
                    raise Exception("Alarm report is not enable.")
                manageone_oc_base_url = rsp_dict["data"]["ALARMSERVERURL"]
            logger.info("The oc url is:" + str(manageone_oc_base_url))
            oc_domain_name = "https://" + manageone_oc_base_url.split(':')[0]
            logger.info("The oc domain name is:" + str(oc_domain_name))
            return oc_domain_name
        except Exception as e:
            logger.error("Query alarm info failed.The reason is:" + str(e))
            return ""
        finally:
            Utils.logout(float_ip, token, session, 2)


def get_eBackup_Driver_nodes(reverse_proxy_ip, db_param_dict):
    return_server_dict = {}
    try:
        file_path = os.path.abspath(__file__ + '/../bin/queryDriverNodes.py')
        fsp_user = "fsp"
        fsp_pwd = db_param_dict['openstack_fsp_pwd']
        fsp_root_pwd = db_param_dict['openstack_root_pwd']
        cps_admin_pwd_unicode = db_param_dict['openstack_cps_admin_pwd']
        cps_admin_pwd = base64.b64encode(cps_admin_pwd_unicode.encode("utf-8")).decode(encoding="utf-8")
        ssh = Ssh()
        ret = ssh.put_file(reverse_proxy_ip, fsp_user, fsp_pwd, file_path, "/home/fsp/")
        if not ret:
            logger.error("Upload %s to %s failed." % (file_path, reverse_proxy_ip))
            raise FCUException(650007, reverse_proxy_ip, fsp_user, '/home/fsp')
        logger.info("Upload queryDriverNode.py to %s successfully." % reverse_proxy_ip)

        query_nodes_cmd = 'cd /home/fsp;chmod +x queryDriverNodes.py;' + \
                          'python queryDriverNodes.py cps_admin \"%s\" upgrade && echo "Success";' % cps_admin_pwd + \
                          '''sed -i '/queryDriverNodes.py/ d' ~/.bash_history;history -c;rm -f /home/fsp/queryDriverNodes.py''' 
        ssh_client = ssh.ssh_create_client(reverse_proxy_ip, fsp_user, fsp_pwd)
        ssh.ssh_send_command(ssh_client, 'su - root', 'Password:', 100)
        ssh.ssh_send_command(ssh_client, fsp_root_pwd, '#', 100)
        result = ssh.ssh_exec_command_return_list(ssh_client, query_nodes_cmd)
        Utils.close_ssh_clinet(ssh_client)
        cps_server_dict = {}
        driver_node_dict = {}
        if -1 != str(result).find("Unsupported-eBackup"):
            logger.info("eBackup is unsupported in this cascaded layer:" + reverse_proxy_ip)
            return {}
        if -1 != str(result).find("Success"):
            for index, val in enumerate(result):
                try:
                    if -1 != val.find("cpsnode"):
                        cps_server_dict = json.loads(val)
                        continue
                    if -1 != val.find("eBackupDriver"):
                        driver_node_dict = json.loads(val)
                        continue
                except Exception as e:
                    logger.error("Convert string to dict failed.The reason is: " + str(e))
                    raise e
        else:
            logger.error("Query eBackup driver nodes failed,the reason is: " + str(result))
            raise Exception(str(result))

        return_server_dict.update(cps_server_dict)
        return_server_dict.update(driver_node_dict)
        logger.info("eBackupDriver:" + str(return_server_dict["eBackupDriver"]))
        logger.info("CpsServer:" + str(return_server_dict["cpsnode"]))
        logger.info("Query eBackup driver nodes successfully.")
        return return_server_dict
    except Exception as e:
        logger.error(e)
        raise e


def get_cascading_fsp_web_client(reverse_ip, port, web_passwd):
    if reverse_ip is None or web_passwd is None:
        raise Exception("openstack_reverse_proxy_ip or openstack_cpsweb_pwd can not be None.")
    auth_provider = {
        "ip": reverse_ip,
        "port": port,
        "user_name": "admin",
        "pwd": web_passwd
    }
    fsp_web_info = (auth_provider, "webUI_rest")
    return g_webui_client_ctrl.apply_client(fsp_web_info, None)


def get_reverse_ip(rest_client, cascaded_region_name):
    logger.info('start get_reverse_ip %s ' % cascaded_region_name)
    url = "api/v1/config/domain"
    cmd = {'body': None, 'method': 'GET', 'uri': url}
    ret = rest_client.exec_cmd(cmd)
    if ret[0] != 200:
        logger.error("Request to get cascaded reverse proxy ip failed,"
                     "status code is %s." % str(ret[0]))
        return ''
    result = ret[2]
    if 'dns_address' in result and result['dns_address']:
        logger.info('The dns_address are:%s' % str(result['dns_address']))
        for dns_address in result['dns_address']:
            if cascaded_region_name in dns_address['domain']:
                return dns_address['ip']
    return ''


def get_all_cascaded_reverse_ips(db_param_dict):
    try:
        url = "api/v1/config/cascade"
        cmd = {'body': None, 'method': 'GET', 'uri': url}
        cascading_webui_client = get_cascading_fsp_web_client(
            db_param_dict["openstack_reverse_proxy_ip"],
            db_param_dict["openstack_external_api_cps_web_port"],
            db_param_dict["openstack_cps_web_pwd"])

        if not cascading_webui_client:
            logger.error("Create cascading webui client failed.")
        ret = cascading_webui_client.exec_cmd(cmd)
        if ret[0] != 200:
            logger.error("Request to get cascaded_ips failed,"
                         "status code is %s." % str(ret[0]))
            return []
        logger.info("Request to get cascaded_ips successfully.")
        result = ret[2]
        if 'cascaded' in result and result['cascaded']:
            cascaded_list = result['cascaded']
            logger.info("All cascaded params are %s" % str(cascaded_list))
        else:
            return []

        all_cascaded_reverse_ip = []
        for each_cascaded in cascaded_list:
            each_reverse_ip = get_reverse_ip(cascading_webui_client,
                each_cascaded["params"]["cascaded_region_name"])
            if each_reverse_ip not in all_cascaded_reverse_ip:
                all_cascaded_reverse_ip.append(each_reverse_ip)
        logger.info("All cascaded reverse_ips are "
                    "%s" % str(all_cascaded_reverse_ip))
        if 0 != len(all_cascaded_reverse_ip):
            logger.info("Start to write all cascaded reverse ips to file.")
            cascaded_reverse_ips_file = get_reverse_proxy_file(db_param_dict["current_region_id"], db_param_dict["openstack_reverse_proxy_ip"])
            cascaded_reverse_ips = ",".join(all_cascaded_reverse_ip)
            fp = open(cascaded_reverse_ips_file, mode='w+', encoding='UTF-8')
            fp.write(cascaded_reverse_ips)
            fp.close()
            logger.info("Write all cascaded reverse ips to file end.")
        return all_cascaded_reverse_ip
    except Exception as e:
        logger.error("Get all cascaded reverse ips failed,the reason is:" + str(e))
        return []


def get_cascaded_reverse_ips(params_dict):
    all_cascaded_reverse_ips = []
    retry_count = 3
    cascaded_reverse_ips_file = get_reverse_proxy_file(params_dict["current_region_id"], params_dict["openstack_reverse_proxy_ip"])
    if os.path.isfile(cascaded_reverse_ips_file):
        with open(cascaded_reverse_ips_file, mode='r', encoding='UTF-8') as fp:
            cascaded_reverse_ips = fp.readline()
        
        all_cascaded_reverse_ips = cascaded_reverse_ips.replace('\n', '').strip(',').split(",")
        if 0 == len(all_cascaded_reverse_ips):
            logger.error("Query all cascaded reverse ips failed by " + cascaded_reverse_ips_file)
            # TODO rm CASCADED_REVERSE_IP_FILE
            if os.path.exists(cascaded_reverse_ips_file):
                os.remove(cascaded_reverse_ips_file)
    else:
        while retry_count > 0:
            all_cascaded_reverse_ips = get_all_cascaded_reverse_ips(params_dict)
            if len(all_cascaded_reverse_ips) != 0:
                break
            retry_count = retry_count - 1
            logger.info("Query all cascaded reverse ips failed,now try again.")
            time.sleep(10)
        if len(all_cascaded_reverse_ips) == 0:
            logger.error("Query all cascaded reverse ips failed.")
            return []
    return all_cascaded_reverse_ips


class eBackupConfig(object):
    def __init__(self, hosts, db_param_dict, node_type, action="upgrade"):
        logger.init("eBackup config")
        self.__db_param_dict = db_param_dict
        self.__node_type = node_type
        self.__action = action
        self.__hosts = hosts

    def get_config(self):
        logger.info("dmk: enter get dmk config step.")
        # 获取安装时候的配置模板信息

        if self.__action == "config":
            return self._config_dmk_config()
        elif self.__action == "upgrade":
            return self._upgrade_dmk_config()
        # 装备config块

        logger.info("dmk: compute dmk params failed.")
        return "", ""

    def _upgrade_dmk_config(self):
        config_val = ""
        if self.__node_type == "datamover":
            config_val = ""
        elif self.__node_type == "workflow":
            config_val = ""

        host_val = "[eBackupService]\n"
        for host in self.__hosts:
            host_val += host + "\n"
        return config_val, host_val

    def _config_dmk_config(self):
        config_val = ""
        if self.__node_type == "datamover":
            config_val = ""
        elif self.__node_type == "workflow":
            config_val = ""

        host_val = "[eBackupService]\n"
        for host in self.__hosts:
            host_val += host + "\n"
        return config_val, host_val


class eBackupDriverConfig(object):
    def __init__(self, hosts_dict, param_dict, one2all=0, action="upgrade"):
        logger.init("eBackup driver config")
        self.__db_param_dict = param_dict
        self.__action = action
        self.__hosts_dict = hosts_dict
        self.__one2all = one2all

    def get_config(self):
        logger.info("dmk: enter get dmk config step.")
        # 获取安装时候的配置模板信息

        if self.__action == "config":
            return self._config_dmk_config()
        elif self.__action == "upgrade":
            return self._upgrade_dmk_config()
        # 装备config块

        logger.info("dmk: compute dmk params failed.")
        return "", ""

    def _upgrade_dmk_config(self):
        cps_user_pwd = self.__db_param_dict['openstack_cps_admin_pwd']
        config_val = "CpsUsername: " + "cps_admin\n" + "CpsPasswd: " + \
                             cps_user_pwd + "\n" + "DriverUpgradeNode_one2all: %s\n" % self.__one2all

        host_val = ""
        if self.__one2all == 1:
            host_val += "[eBackupDriver]\n"
            host_val += self.__hosts_dict["eBackupDriver"][0]
        else:
            if 0 != len(self.__hosts_dict["cpsnode"]):
                host_val += "[cpsnode]\n"
                for ip in self.__hosts_dict["cpsnode"]:
                    host_val += ip + "\n"
            if 0 != len(self.__hosts_dict["eBackupDriver"]):
                host_val += "[eBackupDriver]\n"
                for ip in self.__hosts_dict["eBackupDriver"]:
                    host_val += ip + "\n"

        return config_val, host_val

    def _config_dmk_config(self):
        cps_user_pwd = self.__db_param_dict['openstack_cps_admin_pwd']
        config_val = "CpsUsername: " + "cps_admin\n" + "CpsPasswd: " + \
                             cps_user_pwd + "\n" + "DriverUpgradeNode_one2all: 0\n"
        host_val = "[eBackupDriver]\n"

        host_val += self.__hosts_dict["eBackupDriver"][0]
        return config_val, host_val


class CommonConfig(object):
    def __init__(self, param_dict, pod_id=None, region_id=None):
        self.param_dict = param_dict
        self.pod_id = pod_id
        self.region_id = region_id

    def config(self,operation):
        allowed_operation = ["FspScene"]
        if operation not in allowed_operation:
            raise FCUException(650008,'unsupported operation:' + str(operation))

        if operation == "FspScene":
            workflow_nodes = self.param_dict["eBackup_Workflow_nodes"].replace(" ", "").split(";")
            cmd = '''hcpconffile='/opt/huawei-data-protection/ebackup/microservice/ebk_openstack_vm/conf/hcpconf.ini' ; sed -i 's/FspScene=0/FspScene=1/g' ${hcpconffile} ;grep -w "FspScene=1" ${hcpconffile} && echo "Success" '''
            account_hcp = "hcp"
            account_hcp_passwd = self.param_dict['eBackup_hcp_pwd']
            account_root_passwd = self.param_dict['eBackup_root_pwd']
            for workflow_node in workflow_nodes:
                ssh_client = Ssh.ssh_create_client(workflow_node, account_hcp, account_hcp_passwd)
                Ssh.ssh_send_command(ssh_client, 'su - root', 'Password:', 100)
                Ssh.ssh_send_command(ssh_client, account_root_passwd, '#', 100)
                result = Ssh.ssh_exec_command_return(ssh_client, cmd)
                Utils.close_ssh_clinet(ssh_client)
                if -1 != str(result).find("Success"):
                    logger.info("Change hcpconf.ini of openstack_vm service on node {} Success".format(workflow_node))
                else:
                    logger.error("Change hcpconf.ini of openstack_vm service on node {} Failed".format(workflow_node))
                    raise FCUException(650008, "Change hcpconf.ini of openstack_vm"
                                               " service on node {} Failed".format(workflow_node))
        return True

    def set_cert(self, float_ip):
        token = None
        ssh = None
        ssh_client = None
        lb_float_ip = None
        try:
            cert_port = "26335"
            iam_user = self.param_dict["eBackup_iam_username"]
            iam_password = self.param_dict["eBackup_iam_pwd"]
            region_id = self.param_dict["current_region_id"]
            ip_version = Utils.check_ip_version(float_ip)

            if -1 != Utils.check_ip_version(self.param_dict["ManageOne_global_domain_name"]):
                silvan_url = self.param_dict["ManageOne_global_domain_name"]
            else:
                silvan_url = "console-silvan." + self.param_dict["ManageOne_global_domain_name"]

            if ip_version == 4:
                cert_url = "https://%s:%s" % (silvan_url, cert_port)
            else:
                cert_url = "https://[%s]:%s" % (silvan_url, cert_port)
            logger.info("Begin to config cert info,the silvan url is: " + silvan_url + ":" + cert_port)
            get_lb_float = '''lb_address=`grep -w LoadbalanceAddress /opt/huawei-data-protection/ebackup/conf/hcpconf.ini | awk -F "=" '{print $2}'`; echo $lb_address'''
            ssh = Ssh()
            ssh_client = ssh.ssh_create_client(float_ip, "hcp", self.param_dict["eBackup_hcp_pwd"])
            ssh.ssh_send_command(ssh_client, 'su - root', 'Password:', 100)
            ssh.ssh_send_command(ssh_client, self.param_dict["eBackup_root_pwd"], '#', 100)
            lb_address = ssh.ssh_exec_command_return_list(ssh_client, get_lb_float)
            logger.info("Get lb address:" + str(lb_address))
            lb_float_ip = lb_address[0].strip().replace("\n", "")
            token = Utils.login_governance(lb_float_ip, self.param_dict["eBackup_admin_pwd"], ssh, ssh_client)
            set_cert_cmd = '''lb_address=`grep -w LoadbalanceAddress /opt/huawei-data-protection/ebackup/conf/hcpconf.ini | awk -F "=" '{print $2}'`;''' + \
                           '''/opt/huawei-data-protection/ebackup/sbin/SecurityTool dmk patch $lb_address/v1/srv_governance_inner/settings ''' + \
                           ''' '{"Settings":[{"ConfDomain":"UnifyCert","ConfItem":"ManageOneAddr","ConfValue":"%s"},''' % cert_url + \
                           '{"ConfDomain":"UnifyCert","ConfItem":"CurrentRegion","ConfValue":"%s"},' % region_id + \
                           '{"ConfDomain":"UnifyCert","ConfItem":"OpenstackIAMUserName","ConfValue":"%s"},' % iam_user + \
                           '''{"ConfDomain":"UnifyCert","ConfItem":"OpenstackIAMUserPassword","ConfValue":"%s"}]}' ''' % iam_password + \
                           '''"X-Auth-Token:%s" 2>/dev/null''' % token
            result = ssh.ssh_exec_command_return(ssh_client, set_cert_cmd)
            ssh.ssh_send_command(ssh_client, '''sed -i '/SecurityTool/ d' ~/.bash_history >/dev/null 2>&1;history -c >/dev/null 2>&1;''', '#', 100)
            if -1 != str(result).find("ResponseCode OK"):
                try:
                    rsp_dict = {}
                    for index, val in enumerate(result):
                        if -1 != str(val).find("Data"):
                            rsp_dict = json.loads(result[index].replace('\n', ''))
                            break
                    if not rsp_dict:
                        logger.error("There is no Data in response result,the response is " + str(result))
                        raise Exception("There is no Data in response result,the response is " + str(result))

                    if rsp_dict["Error"]["Code"] != 0:
                        raise Exception("Config cert failed,the error code is" + rsp_dict["Error"]["Code"])

                except Exception as e:
                    logger.error("Config cert failed,the result is" + str(result))
                    raise Exception("Convert result to dict failed.")
            else:
                logger.error("Response Code is not 200")
                return False
            logger.info("Set cert sucessfully.")
            return True
        except Exception as e:
            logger.error("Set cert failed,the reason is " + str(e))
            return False
        finally:
            Utils.logout_governance(lb_float_ip, token, ssh, ssh_client)
            Utils.close_ssh_clinet(ssh_client)

    def set_unified_backup(self, float_ip, manageone_oc_base_url):
        token = None
        ssh = None
        ssh_client = None
        lb_float_ip = None
        try:
            logger.info("Begin to connect manage one unified backup.")
            get_lb_float = '''lb_address=`grep -w LoadbalanceAddress /opt/huawei-data-protection/ebackup/conf/hcpconf.ini | awk -F "=" '{print $2}'`; echo $lb_address'''
            ssh = Ssh()
            ssh_client = ssh.ssh_create_client(float_ip, "hcp", self.param_dict["eBackup_hcp_pwd"])
            ssh.ssh_send_command(ssh_client, 'su - root', 'Password:', 100)
            ssh.ssh_send_command(ssh_client, self.param_dict["eBackup_root_pwd"], '#', 100)
            lb_address = ssh.ssh_exec_command_return_list(ssh_client, get_lb_float)
            logger.info("Get lb address:" + str(lb_address))
            lb_float_ip = lb_address[0].strip().replace("\n", "")
            token = Utils.login_governance(lb_float_ip, self.param_dict["eBackup_admin_pwd"], ssh, ssh_client)
            set_backup_cmd = '''/opt/huawei-data-protection/ebackup/sbin/SecurityTool dmk patch %s/v1/srv_governance_inner/settings ''' % lb_float_ip + \
            ''' '{"Settings":[{"ConfDomain":"UnifyCert","ConfItem":"ManageOneOCAddr","ConfValue":"%s"}]}' "X-Auth-Token:%s" ''' % (manageone_oc_base_url, token)
            
            result = ssh.ssh_exec_command_return(ssh_client, set_backup_cmd)
            ssh.ssh_send_command(ssh_client, '''sed -i '/SecurityTool/ d' ~/.bash_history >/dev/null 2>&1;history -c >/dev/null 2>&1;''', '#', 100)
            if -1 != str(result).find("ResponseCode OK"):
                try:
                    rsp_dict = {}
                    for index, val in enumerate(result):
                        if -1 != str(val).find("Data"):
                            rsp_dict = json.loads(result[index].replace('\n', ''))
                            break
                    if not rsp_dict:
                        logger.error("There is no Data in response result,the response is " + str(result))
                        raise Exception("There is no Data in response result,the response is " + str(result))

                    if rsp_dict["Error"]["Code"] != 0:
                        raise Exception("Config unified backup failed,the error code is" + rsp_dict["Error"]["Code"])

                except Exception as e:
                    logger.error("Config unified backup failed,the result is" + str(result))
                    raise Exception("Convert result to dict failed.")
            else:
                logger.error("Response Code is not 200")
                return False
            logger.info("Config unified backup sucessfully.")
            return True
        except Exception as e:
            logger.error("Config unified backup failed,the reason is:" + str(e))
            return False
        finally:
            Utils.logout_governance(lb_float_ip, token, ssh, ssh_client)
            Utils.close_ssh_clinet(ssh_client)

    def config_openstack_info(self, float_ip):
        token = None
        ssh = None
        ssh_client = None
        lb_float_ip = None
        try:
            openstack_info_dict = Utils.query_openstack_info(float_ip, self.param_dict["eBackup_admin_pwd"])
            if not openstack_info_dict:
                logger.error("Query openstack info failed.")
                raise Exception("Query openstack info failed.")
            iam_user = self.param_dict["eBackup_iam_pwd"]
            iam_password = self.param_dict["eBackup_iam_username"]
            auth = openstack_info_dict["AUTHURL"]
            cinder = openstack_info_dict["CINDERURL"]
            neutron = openstack_info_dict["NEUTRONURL"]
            nova = openstack_info_dict["NOVAURL"]
            api_gw = self.param_dict["apicom_domain_name"]
            get_lb_float = '''lb_address=`grep -w LoadbalanceAddress /opt/huawei-data-protection/ebackup/conf/hcpconf.ini | awk -F "=" '{print $2}'`; echo $lb_address'''
            ssh = Ssh()
            ssh_client = ssh.ssh_create_client(float_ip, "hcp", self.param_dict["eBackup_hcp_pwd"])
            ssh.ssh_send_command(ssh_client, 'su - root', 'Password:', 100)
            ssh.ssh_send_command(ssh_client, self.param_dict["eBackup_root_pwd"], '#', 100)
            lb_address = ssh.ssh_exec_command_return_list(ssh_client, get_lb_float)
            logger.info("Get lb address:" + str(lb_address))
            lb_float_ip = lb_address[0].strip().replace("\n", "")
            token = Utils.login_governance(lb_float_ip, self.param_dict["eBackup_admin_pwd"], ssh, ssh_client)

            config_openstack_cmd = '''lb_address=`grep -w LoadbalanceAddress /opt/huawei-data-protection/ebackup/conf/hcpconf.ini | awk -F "=" '{print $2}'`;''' + \
            '''/opt/huawei-data-protection/ebackup/sbin/SecurityTool dmk patch $lb_address/v1/srv_governance/service_settings ''' + \
            ''' '{"ServiceName":["ebk_openstack_vm", "ebk_openstack_vmware", "ebk_alarm", "ebk_iam"],"Settings":[{"ConfDomain":"OpenstackConfig","ConfItem": "OpenstackConfigValue",''' + \
            '''"ConfValue": "{\\"AuthPassword\\":\\"%s\\",\\"AuthType\\":\\"IAM\\",\\"AuthURL\\":\\"%s\\",\\"AuthUserName\\":\\"%s\\",\\"CinderURL\\":\\"%s\\",\\"NeutronURL\\":\\"%s\\",\\"NovaURL\\":\\"%s\\",\\"ApigwURL\\":\\"https://%s\\"}"}]}' "X-Auth-Token:%s" 2>/dev/null''' \
            % (iam_user, auth, iam_password, cinder, neutron, nova, api_gw, token)
            result = ssh.ssh_exec_command_return(ssh_client, config_openstack_cmd)
            ssh.ssh_send_command(ssh_client, '''sed -i '/SecurityTool/ d' ~/.bash_history >/dev/null 2>&1;history -c >/dev/null 2>&1;''', '#', 100)
            if -1 != str(result).find("ResponseCode OK"):
                try:
                    rsp_dict = {}
                    for index, val in enumerate(result):
                        if -1 != str(val).find("Data"):
                            rsp_dict = json.loads(result[index].replace('\n', ''))
                            break
                    if not rsp_dict:
                        logger.error("There is no Data in response result,the response is " + str(result))
                        raise Exception("There is no Data in response result,the response is " + str(result))

                    if rsp_dict["Error"]["Code"] != 0:
                        raise Exception("Config openstack failed,the error code is" + rsp_dict["Error"]["Code"])

                except Exception as e:
                    logger.error("Config openstack failed,the result is" + str(result))
                    raise Exception("Convert result to dict failed.")
            else:
                logger.error("Response Code is not 200")
                return False
            logger.info("Config openstack info successfully.")
            return True
        except Exception as e:
            logger.error("Config opensack failed.Occur exception: " + str(e))
            return False
        finally:
            Utils.logout_governance(lb_float_ip, token, ssh, ssh_client)
            Utils.close_ssh_clinet(ssh_client)

    def config_service_monitor(self):
        workflow_ip = self.param_dict["eBackup_Workflow_nodes"].split(";")
        datamover_ip = self.param_dict["eBackup_Datamover_nodes"].replace("|", ";").split(";")
        all_ip_list = workflow_ip + datamover_ip
        hosts = []
        templates = ["eBackup_server_template_01", "eBackup_server_template_02", "os_template"]
        for ip in all_ip_list:
            for template_id in templates:
                ebackup_node = ServiceNodeCfg(ip, template_id, "eBackup_log")
                hosts.append(ebackup_node)
        service_m_cfg = ServiceMonitorCfg("eBackup",
                                          "eBackup",
                                          self.param_dict["region_id"],
                                          "eBackup",
                                          "IAAS",
                                          hosts)
        if not set_service_m_cfg(self.pod_id, service_m_cfg):
            return True

    def config_manager_address_on_server(self, float_ip):
        token = None
        ssh = None
        ssh_client = None
        lb_float_ip = None
        try:
            ip_version = Utils.check_ip_version(float_ip)
            manager_address = Utils.find_float_ip(self.param_dict["eBackup_Workflow_nodes"].split(";"),
                                                  self.param_dict["eBackup_hcp_pwd"],
                                                  self.param_dict["eBackup_root_pwd"])
            if ip_version == 4:
                manager_address = manager_address + ":8088"
            else:
                manager_address = "[%s]:8088" % manager_address
            get_lb_float = '''lb_address=`grep -w LoadbalanceAddress /opt/huawei-data-protection/ebackup/conf/hcpconf.ini | awk -F "=" '{print $2}'`; echo $lb_address'''
            ssh = Ssh()
            ssh_client = ssh.ssh_create_client(float_ip, "hcp", self.param_dict["eBackup_hcp_pwd"])
            ssh.ssh_send_command(ssh_client, 'su - root', 'Password:', 100)
            ssh.ssh_send_command(ssh_client, self.param_dict["eBackup_root_pwd"], '#', 100)
            lb_address = ssh.ssh_exec_command_return_list(ssh_client, get_lb_float)
            logger.info("Get lb address:" + str(lb_address))
            lb_float_ip = lb_address[0].strip().replace("\n", "")
            token = Utils.login_governance(lb_float_ip, self.param_dict["eBackup_admin_pwd"], ssh, ssh_client)
            config_manager_address_cmd = '''/opt/huawei-data-protection/ebackup/sbin/SecurityTool dmk patch %s/v3/auth/set_manager_info '{"Settings":[{"ConfDomain" : "eBackupManagerConfig","ConfItem" : "eBackupManagerConfigValue","ConfValue" : "{\\"URL\\":\\"%s\\"}"}]}' "X-Auth-Token:%s"  2>/dev/null''' \
                         % (lb_float_ip, manager_address, token)
            result = ssh.ssh_exec_command_return(ssh_client, config_manager_address_cmd)
            ssh.ssh_send_command(ssh_client, '''sed -i '/SecurityTool/ d' ~/.bash_history >/dev/null 2>&1;history -c >/dev/null 2>&1;''', '#', 100)
            if -1 != str(result).find("ResponseCode OK"):
                try:
                    rsp_dict = {}
                    for index, val in enumerate(result):
                        if -1 != str(val).find("Data"):
                            rsp_dict = json.loads(result[index].replace('\n', ''))
                            break
                    if not rsp_dict:
                        logger.error("There is no Data in response result,the response is " + str(result))
                        raise Exception("There is no Data in response result,the response is " + str(result))

                    if rsp_dict["Error"]["Code"] != 0:
                        raise Exception("Config manager address on server failed,the error code is:"
                                        + rsp_dict["Error"]["Code"])

                except Exception as e:
                    logger.error("Config manager address on server failed,the result is" + str(result))
                    raise Exception("Convert result to dict failed,the reason is" + str(e))
            else:
                logger.error("Response Code is not 200")
                return False
            logger.info("Config manager address on server successfully.")
            return True
        except Exception as e:
            logger.error("Config manager address on server.Occur exception: " + str(e))
            return False
        finally:
            Utils.logout_governance(lb_float_ip, token, ssh, ssh_client)
            Utils.close_ssh_clinet(ssh_client)

    def config_alarm_info(self, float_ip):
        token = ""
        session = ""
        try:
            logger.info("Begin to config alarm info at host:[%s]" % float_ip)
            oc_domain_name = self.param_dict["ManageOne_oc_external_global_domain_name"]
            if oc_domain_name is None or 0 == len(oc_domain_name) or -1 != Utils.check_ip_version(oc_domain_name):
                logger.info("ManageOne_oc_external_global_domain_name is null or ip address,skip to config alram info.")
                return True
            ip_version = Utils.check_ip_version(float_ip)
            if ip_version == 4:
                url = "https://%s:8088/rest/dev/alarm_settings/default" % float_ip
            else:
                url = "https://[%s]:8088/rest/dev/alarm_settings/default" % float_ip

            token, session = Utils.login(float_ip, self.param_dict["eBackup_admin_pwd"], 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=2;CSRF_IBASE_TOKEN=%s' % (session, 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"
                                 % (float_ip, rsp_dict["error"]["description"]))
                    raise Exception(rsp_dict["error"]["description"])

                if "ALARMSERVERURL" not in rsp_dict["data"] or 0 == len(rsp_dict["data"]["ALARMSERVERURL"]):
                    logger.error("No alarm report is not configured.,the step will be skipped.")
                    return True
                oc_port = rsp_dict["data"]["ALARMSERVERURL"].split(":")[1]
                if oc_port is None or len(oc_port) == 0:
                    logger.error("oc_port is empty.")
                    raise Exception("oc_port is empty.")
            else:
                logger.error("Response status code is not 200.The url is" + url)
                raise Exception("Response status code is not 200.")
            if -1 == Utils.check_ip_version(rsp_dict["data"]["ALARMSERVERURL"].split(":")[0]):
                logger.info("The oc alarm is domain,no need to update.")
                return True
            data = '{"ALARMSERVERURL": "oc.%s:%s"}'\
                   % (self.param_dict["ManageOne_oc_external_global_domain_name"], oc_port)
            rsp = requests.put(url=url, headers=header, data=data, 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("Config alarm info failed on [%s],the description is:%s"
                                 % (float_ip, rsp_dict["error"]["description"]))
                    raise Exception(rsp_dict["error"]["description"])

            else:
                logger.error("Response status code is not 200.The url is" + url)
                raise Exception("Response status code is not 200.")

            logger.info("Config alarm info successfully.")

            return True
        except Exception as e:
            logger.error("Config alarm info failed.The reason is: " + str(e))
            return False
        finally:
            Utils.logout(float_ip, token, session, 2)

    def config_operation_log_reporting(self, float_ip):
        token = ""
        session = ""
        try:
            logger.info("Begin to config operation_log_reporting info at host:[%s]" % float_ip)

            global_domain_name = self.param_dict["ManageOne_global_domain_name"]
            if -1 != Utils.check_ip_version(global_domain_name):
                logger.info("ManageOne_global_domain_name is ip,skip to config operation log reporting info.")
                return True

            ip_version = Utils.check_ip_version(float_ip)
            if ip_version == 4:
                url = "https://%s:8088/rest/dev/syslog_settings/default" % float_ip
            else:
                url = "https://[%s]:8088/rest/dev/syslog_settings/default" % float_ip

            token, session = Utils.login(float_ip, self.param_dict["eBackup_admin_pwd"], 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=2;CSRF_IBASE_TOKEN=%s' % (session, 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 operation_log_reporting info failed on [%s],the description is:%s"
                                 % (float_ip, rsp_dict["error"]["description"]))
                    raise Exception(rsp_dict["error"]["description"])
                if "SERVERURL" not in rsp_dict["data"] or 0 == len(rsp_dict["data"]["SERVERURL"]):
                    logger.error("No operation log report is configured,the step will be skipped.")
                    return True
                lvs_port = rsp_dict["data"]["SERVERURL"].split(":")[1]
                if lvs_port is None or len(lvs_port) == 0:
                    logger.error("lvs_port is empty.")
                    raise Exception("lvs_port is empty.")
            else:
                logger.error("Response status code is not 200.The url is" + url)
                raise Exception("Response status code is not 200.")
            data = '{"ISON":"1","SERVERURL":"mo-lvs.%s:%s"}'\
                   % (self.param_dict["ManageOne_global_domain_name"], lvs_port)
            rsp = requests.put(url=url, headers=header, data=data, 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("Config operation_log_reporting info failed on [%s],the description is:%s"
                                 % (float_ip, rsp_dict["error"]["description"]))
                    raise Exception(rsp_dict["error"]["description"])
            else:
                logger.error("Response status code is not 200.The url is" + url)
                raise Exception("Response status code is not 200.")

            logger.info("Config operation_log_reporting info successfully.")
            return True
        except Exception as e:
            logger.error("Config operation_log_reporting info failed.The reason is: " + str(e))
            return False
        finally:
            Utils.logout(float_ip, token, session, 2)

    def update_server_info(self):
        try:
            workflow_ips = self.param_dict["eBackup_Workflow_nodes"].split(';')
            # ip : id
            workflow_dict = {}
            auth_provider = {
                "url": self.param_dict['keystoneurl'].split('/identity/v3')[0],
                "version": "v3",
                "user_name": "cloud_admin",
                "tenant_name": "dc_system_" + self.param_dict['openstack_region'].split('.')[-1],
                "region": self.param_dict['openstack_region'],
                "pwd": self.param_dict['openstack_cloud_admin_pwd']
            }
            host_and_tool = (auth_provider, "openstack_compute")
            server_operate = ServerOperate()
            vm_list = server_operate.list_server(host_and_tool)
            for vm in vm_list['servers']:
                for net_plane, netcard_list in list(vm['addresses'].items()):
                    for netcard in netcard_list:
                        if 'addr' in netcard and netcard['addr'] in workflow_ips:
                            workflow_dict.update({netcard['addr']: vm['id']})
                            logger.info("Host ip:%s, Host id:%s" % (netcard['addr'], vm['id']))
                            break
            if len(workflow_dict) != len(workflow_ips):
                logger.error("Query all host[%s] ids failed." % str(workflow_ips))
                return False

            all_result = True
            manager_ip = Utils.find_admin_ip(workflow_ips, self.param_dict['eBackup_hcp_pwd'],
                                             self.param_dict['eBackup_root_pwd'])
            for ip, id in list(workflow_dict.items()):
                if ip == manager_ip:
                    vm_name = 'eBackup-Manager'
                else:
                    vm_name = 'eBackup-Workflow'
                result = server_operate.update_server(name=vm_name, server_id=id, host_and_tool=host_and_tool)
                if not result.get('result'):
                    logger.error("Update the name of the host(%s) to %s failed." % (ip, vm_name))
                    all_result = False
                logger.info("Update the name of the host(%s) to %s successfully." % (ip, vm_name))
            if not all_result:
                logger.error("Update all name of Manager&Workflow VMs failed.")
            else:
                logger.info("Update all name of Manager&Workflow VMs successfully.")

            return all_result
        except Exception as e:
            logger.error("Update all name of Manager&Workflow VMs failed.The reason is: " + str(e))
            return False


def get_ebackup_driver_nodes_from_file(file_path):
    if not os.path.exists(file_path):
        logger.error("There is no %s existing." % file_path)
        return {}
    driver_host_list = []
    driver_host_dict = {}
    with open(file_path, mode='r') as fp:
        driver_host_list = fp.readlines()
    if 2 != len(driver_host_list):
        logger.error("There is no cps-server node or eBackup driver node in:" + str(file_path))
        raise Exception("There is no cps-server node or eBackup driver node in:" + str(file_path))
    driver_host_dict['cpsnode'] = driver_host_list[0].replace('\n', '').strip(',').split(',')
    logger.info("Get cps node form {0}:{1}".format(file_path, str(driver_host_dict['cpsnode'])))
    driver_host_dict['eBackupDriver'] = driver_host_list[1].replace('\n', '').strip(',').split(',')
    logger.info("Get ebackup driver node from {0}:{1}.".format(file_path, str(driver_host_dict['eBackupDriver'])))
    return driver_host_dict


def ping_in_windows(host, retry_times=3):
    try:
        logger.info("Begin to ping {}.".format(host))
        cmd = 'ping -w 1000 -n %d %s' % (4, host)
        for i in range(0, retry_times):
            time.sleep(2)
            ping_process = subprocess.Popen(args=cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
            (std_output, err_output) = ping_process.communicate()
            if str(std_output).find('TTL=') >= 0:
                logger.info("Ping {} successfully.".format(host))
                return True
        logger.error("Ping {} failed.".format(host))
        return False
    except Exception as e:
        logger.error("ping host failed,the reason is:" + str(e))
        raise FCUException(650008, str(e))


def ping_reverse_proxy_ips(check_result, key, host_list, reverse_proxy_ip, current_region_id):
    try:
        logger.info("Begin to ping {}".format(','.join(host_list)))
        unpassed_ips = []
        for ip in host_list:
            is_true = ping_in_windows(ip)
            if not is_true:
                unpassed_ips.append(ip)
                logger.error("ping {} failed.".format(ip))
        if 0 != len(unpassed_ips):
            cascaded_reverse_ips_file = get_reverse_proxy_file(current_region_id, reverse_proxy_ip)
            check_result.set_check_result(param_keys=[key], status=500,
                                          error_msg=FCUException(650024, ','.join(unpassed_ips),
                                                                 ','.join(unpassed_ips), cascaded_reverse_ips_file))
            return False
        logger.info("Ping {} successfully.".format(','.join(host_list)))
        return True
    except Exception as e:
        check_result.set_check_result(param_keys=[key], status=500, error_msg=FCUException(650008, str(e)))
        return False


def format_check_results(check_results, precheck_result):
    logger.info("Begin to format precheck result...")
    for (key, val) in precheck_result.items():
        if 0 == len(val):
            check_result = CheckResult(itemname_ch=g_check_item[key]['name_cn'],
                                       itemname_en=g_check_item[key]['name_en'], status="success")
        else:
            unpassed_nodes = []
            error_msg_temp = {}
            error_msg = {}
            
            for (ip, msg) in list(val.items()):
                unpassed_nodes.append(ip)
                if msg not in error_msg:
                    error_msg_temp.update({msg:[ip]})
                else:
                    error_msg_temp[msg].append(ip)

            for (msg, ips) in list(error_msg_temp.items()):
                error_msg.update({','.join(ips):msg})
            error_description = str(list(error_msg.values())[0]) if 1 == len(error_msg) else str(error_msg)
            check_result = CheckResult(itemname_ch=g_check_item[key]['name_cn'],
                                       itemname_en=g_check_item[key]['name_en'], status="failure",
                                       error_msg_cn=FCUException(g_check_item[key]['error_code'],
                                                                 ','.join(unpassed_nodes), error_description))
        check_results.append(check_result)
    logger.info("Format precheck result completed.")
    

def precheck_ebackup(check_results, host_list, hcp_password, root_password, update_scene, dmk_float_Ip, version):
    ssh_client = None
    try:
        ssh = Ssh()
        check_flag = True
        precheck_result = {
            "cpu_health": {},
            "disk_health": {},
            "disk_space": {},
            "network_health": {},
            "service_health": {},
            "ha_health": {}
        }
        precheck_script = os.path.abspath(__file__ + '/../bin/precheck_ebackup.sh')
        precheck_cmd = 'sh /home/hcp/precheck_ebackup.sh %s %s %s && echo "Success"' \
                       % (update_scene,  dmk_float_Ip, version)
        logger.info("Begin to precheck eBackup: " + str(host_list))
        for ip in host_list:
            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)
            ssh.ssh_send_command(ssh_client, 'rm -rf /home/hcp/precheck_ebackup.sh', '#', 100)
            ret = ssh.put_file(ip, "hcp", hcp_password, precheck_script, "/home/hcp/")
            if not ret:
                logger.error("Upload %s to host(%s) failed." % (precheck_script, ip))
                raise FCUException(650007, ip, "/home/hcp", "hcp")
            ret = ssh.ssh_exec_command_return_list(ssh_client, precheck_cmd)
            logger.info("Excute precheck command result:" + str(ret))
            if -1 == str(ret).find('Success'):
                raise FCUException(650008, "Exception occurs when excute cmd [{0}] on {1}".format(precheck_cmd, ip))
            ret = ssh.ssh_exec_command_return_list(ssh_client, "cat /home/hcp/precheck_result")
            Utils.close_ssh_clinet(ssh_client)
            for item in ret:
                key_val = item.strip().replace('\n', '').split(':')
                key = key_val[0]
                val = key_val[1]
                logger.info("[Precheck], IP:{0}, check_item:{1}, check_result:{2}".format(ip, key, val))
                if val != 'pass':
                    precheck_result[key].update({ip: val})
                    check_flag = False
                    logger.error("[Precheck], IP:{0}, check_item:{1}, check_result:{2}".format(ip, key, val))
                else:
                    continue
        format_check_results(check_results, precheck_result)
        logger.info("Precheck eBackup completed: " + str(host_list))
        logger.info("The precheck result is:" + str(check_flag))
        return check_flag

    except Exception as e:
        logger.error("Exception occurs when do the precheck:" + str(e))
        raise e
    finally:
        Utils.close_ssh_clinet(ssh_client)


def get_dmk_precheck_result(check_results, host_list, hcp_password, root_password, version):
    ssh_client = None
    try:
        precheck_result = {
            "micro_service_health": {},
            "version_compatibility": {}
        }
        ssh = Ssh()
        check_flag = True
        logger.info("Begin to get dmk precheck result: " + str(host_list))
        for ip in host_list:
            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)
            ret = ssh.ssh_exec_command_return_list(ssh_client, '''grep "System Version" /opt/huawei-data-protection/ebackup/conf/versions.conf | awk -F "=" '{print $2}' ''')
            current_version = ret[0].strip().replace("\n", "")
            logger.info("Current version is " + str(current_version))
            if current_version == version:
                logger.info("Current version is {},No need to do this.".format(current_version))
                continue
            ret = ssh.ssh_exec_command_return_list(ssh_client, "test -e /tmp/upgrade/prechk_result && echo Success")
            logger.info("Check if the dmk precheck result file exists:" + str(ret))
            if -1 == str(ret).find("Success"):
                precheck_result['micro_service_health'].update({ip: "Precheck failed,please view the details on DMK."})
                precheck_result['version_compatibility'].update({ip: "Precheck failed,please view the details on DMK."})
                logger.error("There is no /tmp/upgrade/prechk_result existing.")
                continue

            ret = ssh.ssh_exec_command_return_list(ssh_client, "cat /tmp/upgrade/prechk_result")
            logger.info("Get DMK check result:" + str(ret))
            if -1 == str(ret).find("MicroServicePreCheck.0"):
                precheck_result['micro_service_health'].update({ip: "Micro service status is abnormal"})
                logger.error("[Precheck], IP:{0}, check_item:{1}, check_result:{2}".format(ip, 'micro_service_health', 'Micro service status is abnormal'))

            if -1 == str(ret).find("SysCompatibleCheck.0"):
                precheck_result['version_compatibility'].update({ip: "Version incompatibility"})
                logger.error("[Precheck], IP:{0}, check_item:{1}, check_result:{2}".format(ip, 'version_compatibility', 'Version incompatibility'))
            Utils.close_ssh_clinet(ssh_client)
        format_check_results(check_results, precheck_result)
        logger.info("Get dmk precheck result completed: " + str(host_list))
        logger.info("The precheck result is:" + str(check_flag))
        return check_flag
    except Exception as e:
        logger.error("Exception occurs when get dmk precheck result:" + str(e))
        raise e
    finally:
        Utils.close_ssh_clinet(ssh_client)


def get_deploy_info_from_cmdb(project_id, region_id):
    # input: project_id
    # output: dict
    #    'eBackup_Datamover_nodes': {[]}
    #    'eBackup_Workflow_nodes':{[]}
    #    'openstack_reverse_proxy_ip': ''
    try:
        from utils.business.manageone_cmdb_util import ManageOneCmdbUtil
        logger.info("Begin to query ebackup deploy info from cmdb...")
        deploy_info_dict = {
            'eBackup_Datamover_nodes': {},
            'eBackup_Workflow_nodes': [],
            'openstack_reverse_proxy_ip': ''
        }
        cmdb = ManageOneCmdbUtil(project_id)
        ebackup_nodes_list = cmdb.get_deploy_node_info(region_id, 'eBackup')
        if 0 == len(ebackup_nodes_list):
            logger.error("Query ebackup nodes info failed.")
            raise Exception("Query ebackup nodes info failed.")
        for node in ebackup_nodes_list:
            if node["name"] in ["eBackup-Manager", "eBackup-Workflow"]:
                deploy_info_dict['eBackup_Workflow_nodes'].append(node['ipAddresses'][0]['ip'])
            elif -1 != node["name"].find("eBackup_service"):
                group_name = node["name"][:-1] + 's'
                if group_name not in deploy_info_dict['eBackup_Datamover_nodes']:
                    deploy_info_dict['eBackup_Datamover_nodes'].update({group_name: [node['ipAddresses'][0]['ip']]})
                else:
                    deploy_info_dict['eBackup_Datamover_nodes'][group_name].append(node['ipAddresses'][0]['ip'])
            else:
                logger.error("Parse ebackup nodes info failed.")
                raise Exception("Parse ebackup nodes info failed.")

        openstack_info = cmdb.get_cloud_service_info(region_id, 'OpenStack')
        if 0 == len(openstack_info):
            logger.error("Query openstack deploy info failed.")
            raise Exception("Query openstack deploy info failed.")

        for openstack in openstack_info:
            if openstack['indexName'] == 'OpenStack':
                for item in openstack['extendInfos']:
                    if -1 != str(item).find('openstack_reverse_proxy_ip'):
                        deploy_info_dict['openstack_reverse_proxy_ip'] = item['value']
                        break
                if 0 != len(deploy_info_dict['openstack_reverse_proxy_ip']):
                    logger.info("The openstack reverse proxy ip is:" +
                                str(deploy_info_dict['openstack_reverse_proxy_ip']))
                    break

        if 0 == len(deploy_info_dict['openstack_reverse_proxy_ip']):
            logger.error("Get openstack reverse proxy ip failed.")
            raise Exception("Get openstack reverse proxy ip failed.")

        logger.info("Query ebackup deploy info completed: " + str(deploy_info_dict))
        return deploy_info_dict
    except Exception as e:
        logger.info("Exception occurs when query ebackup deploy info: " + str(e))
        raise e


def check_access_status(check_results, web_ip, admin_pwd, role):
    token = ""
    session = ""
    running_status = {
        'offline': [],
        'partial': []
    }
    try:
        logger.info("Begin to check access status at host:[%s]" % web_ip)
        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_pwd, 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=2;CSRF_IBASE_TOKEN=%s' % (session, 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 access status failed on [%s],the description is:%s"
                             % (web_ip, rsp_dict["error"]["description"]))
                raise Exception(rsp_dict["error"]["description"])
            for node in rsp_dict['data']:
                if node['RUNNINGSTATUS'] == '28':
                    running_status['offline'].append(node['MANAGEMENTIP'])
                    logger.error("The access status of {} is Inaccessible".format(node['MANAGEMENTIP']))
                elif node['RUNNINGSTATUS'] == '30':
                    running_status['partial'].append(node['MANAGEMENTIP'])
                    logger.error("The access status of {} is Partially accessible".format(node['MANAGEMENTIP']))
                else:
                    logger.info("The access status of {} is Accessible".format(node['MANAGEMENTIP']))
        else:
            logger.error("Response status code is not 200.The url is" + url)
            raise Exception("Response status code is not 200.")
        logger.info("Check access status completed,the check reuslt is: " + str(running_status))
        key = 'access_status'
        if 0 != len(running_status['offline']) or 0 != len(running_status['partial']):
            logger.error("Some nodes access status is abnormal: " + str(running_status))
            description = "Login https://{}:8088 for details.".format(web_ip)
            abnormal_nodes = running_status['offline'] + running_status['partial']
            check_result = CheckResult(itemname_ch=g_check_item[key]['name_cn'],
                                       itemname_en=g_check_item[key]['name_en'], status="failure",
                                       error_msg_cn=FCUException(g_check_item[key]['error_code'],
                                                                 ','.join(abnormal_nodes), description))
            check_results.append(check_result)
            return False
        else:
            # Set check result to success when all group nodes has been checked.
            # check_result = CheckResult(itemname_ch=g_check_item[key]['name_cn'],
            #                            itemname_en=g_check_item[key]['name_en'], status="success")
            # check_results.append(check_result)
            logger.info("All nodes access status is normal.")
            return True
    except Exception as e:
            logger.error("Query access status failed.The reason is: " + str(e))
            return False
    finally:
            Utils.logout(web_ip, token, session, role)
