# -*- coding:utf-8 -*-
import os
from utils.common.fic_base import StepBaseInterface
from utils.common.message import Message
import utils.common.log as logger
from utils.business.dmk_util import DmkApi
from plugins.eBackup.common.eBackupUpgrade import eBackupUpgrader
from plugins.eBackup.common.util import get_eBackup_Driver_nodes, precheck_ebackup, \
    get_dmk_precheck_result, check_access_status
from plugins.eBackup.common.util import get_cascaded_reverse_ips
from utils.common.exception import FCUException
from utils.DBAdapter.DBConnector import BaseOps
from utils.common.ssh_util import Ssh
from utils.business.project_util import ProjectApi
from plugins.eBackup.common.util import Utils, g_check_item
from platforms.upgradecheck.check_result import CheckResult

eBackup_Driver_status_check_SUCCESS = [  
    CheckResult(itemname_ch="是否存在未安装eBackup driver的fsp集群",
                itemname_en="If there is no eBackup Driver in this fsp cluster", status="success")
]


class DatamoverPrecheck(StepBaseInterface):
    def __init__(self, project_id, pod_id, regionid_list):
        super(DatamoverPrecheck, self).__init__(project_id, pod_id, regionid_list)
        self.project_id = project_id
        self.pod_id = pod_id
        self.regionid_list = regionid_list
        self.__dmk_util = DmkApi()
        self.param_dict = Utils.init_system_params(project_id, regionid_list[0])

    def execute(self, project_id, pod_id, regionid_list):
        try:
            check_results = []
            server_ips = self.param_dict['eBackup_Datamover_nodes']
            server_ips = server_ips.replace(" ", "").replace("|", ";").split(";")
            self.save_eBackup_version(server_ips[0])
            logger.info("Begin to precheck nodes:" + str(server_ips))
            # 1.precheck by precheck_ebackup.sh
            logger.info("Begin to precheck nodes({}) by HCU firstly.".format(str(server_ips)))
            is_ture = precheck_ebackup(check_results, server_ips, self.param_dict['eBackup_hcp_pwd'],
                                       self.param_dict['eBackup_root_pwd'], self.param_dict['update_scene'],
                                       self.param_dict['dmk_floatIp'], self.param_dict['eBackup_Version'])
            if not is_ture:
                logger.error("Precheck by HCU failed.")
                return Message(200, check_results=check_results)
            # 2.check acess status
            for group in self.param_dict['eBackup_Datamover_nodes'].split('|'):
                group_ips = group.split(';')
                web_ip = Utils.find_float_ip(group_ips, self.param_dict['eBackup_hcp_pwd'],
                                             self.param_dict['eBackup_root_pwd'])
                is_true = check_access_status(check_results, web_ip, self.param_dict['eBackup_admin_pwd'], 1)
                if not is_true:
                    logger.error("Precheck assess status by FCU failed.")
                    return Message(200, check_results=check_results)
            key = 'access_status'
            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)
            # 3.precheck by DMK
            logger.info("Begin to precheck nodes({}) by DMK secondly.".format(str(server_ips)))
            ebackup_upgrade = eBackupUpgrader(server_ips, self.param_dict, "datamover")
            is_true = ebackup_upgrade.precheck()

            if not is_true:
                logger.error("Precheck by DMK failed.")
                raise FCUException(650036)
            
            logger.info("Begin to get DMK precheck result.")
            is_true = get_dmk_precheck_result(check_results, server_ips, self.param_dict['eBackup_hcp_pwd'],
                                              self.param_dict['eBackup_root_pwd'], self.param_dict['eBackup_Version'])
            if not is_true:
                logger.error("Prechecking is unpassed by DMK.")
            logger.info("Precheck nodes({}) completed.".format(server_ips))
            return Message(200, check_results=check_results)
        except FCUException as e:
            logger.error("Do precheck task on DMK failed.")
            return Message(500, e)

        except Exception as e:
            logger.error("Failed to exec precheck ,the reason is %s" % e)
            return Message(500, error_msg_cn="升级前检查出现异常，请查看日志并重试",
                           error_msg_en="Exception occurs while prechecking,please check the log and try again.")

    def rollback(self, project_id, pod_id, regionid_list):
        return Message(200)

    def retry(self, project_id, pod_id, regionid_list):
        return self.execute(project_id, pod_id, regionid_list)

    def save_eBackup_version(self,server_ip):
        try:
            account_hcp = "hcp"
            account_hcp_passwd = self.param_dict['eBackup_hcp_pwd']
            account_root_passwd = self.param_dict['eBackup_root_pwd']
            version_check_cmds = "showsys  | grep -w \"Product Version\" | " \
                                 "awk -F '|' '{print $2}' |sed s/[[:space:]]//g"
            SC = Ssh()
            ssh_client = SC.ssh_create_client(server_ip, account_hcp, account_hcp_passwd)
            SC.ssh_send_command(ssh_client, 'su - root', 'Password:', 100)
            SC.ssh_send_command(ssh_client, account_root_passwd, '#', 100)
            result = SC.ssh_exec_command_return_list(ssh_client, version_check_cmds)
            SC.ssh_close(ssh_client)
            
            origin_version = result[0].strip().replace('\n', '')
            logger.info("Save eBackup version is " + origin_version)
            projectApi = ProjectApi()
            projectApi.save_version_info(self.project_id, "eBackup",
                                         {"Originalversion": origin_version,
                                          "Targetversion": self.param_dict["eBackup_Version"]})
        except Exception as e:
            raise e


class WorkflowPrecheck(StepBaseInterface):
    def __init__(self, project_id, pod_id, regionid_list):
        super(WorkflowPrecheck, self).__init__(project_id, pod_id, regionid_list)
        self.project_id = project_id
        self.pod_id = pod_id
        self.regionid_list = regionid_list
        self.__dmk_util = DmkApi()
        self.param_dict = Utils.init_system_params(project_id, regionid_list[0])

    def execute(self, project_id, pod_id, regionid_list):
        try:
            check_results = []
            server_ips = self.param_dict['eBackup_Workflow_nodes']
            server_ips = server_ips.replace(" ", "").replace("|", ";").split(";")

            logger.info("Begin to precheck nodes:" + str(server_ips))
            # 1.precheck by precheck_ebackup.sh
            logger.info("Begin to precheck nodes({}) by HCU firstly.".format(str(server_ips)))
            is_ture = precheck_ebackup(check_results, server_ips, self.param_dict['eBackup_hcp_pwd'],
                                       self.param_dict['eBackup_root_pwd'], self.param_dict['update_scene'],
                                       self.param_dict['dmk_floatIp'], self.param_dict['eBackup_Version'])
            if not is_ture:
                logger.error("Precheck by HCU failed.")
                return Message(200, check_results=check_results)

            # 2.check acess status

            web_ip = Utils.find_float_ip(server_ips, self.param_dict['eBackup_hcp_pwd'],
                                         self.param_dict['eBackup_root_pwd'])
            is_true = check_access_status(check_results, web_ip, self.param_dict['eBackup_admin_pwd'], 2)
            if not is_true:
                logger.error("Precheck assess status by FCU failed.")
                return Message(200, check_results=check_results)
            key = 'access_status'
            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)
            # 3.just for workflow at the time,it will be removed in next version.
            manageone_oc_url = Utils.query_alarm_info(web_ip, self.param_dict['eBackup_admin_pwd'])
            key = 'alarm_reporting'
            if 0 != len(manageone_oc_url):
                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)
            else:
                error_description = "Alarm reporting function is not configured."
                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'],
                                                                     web_ip, error_description))
                check_results.append(check_result)
                return Message(200, check_results=check_results)
            
            # 3.precheck by DMK
            logger.info("Begin to precheck nodes({}) by DMK secondly.".format(str(server_ips)))
            ebackup_upgrade = eBackupUpgrader(server_ips, self.param_dict, "workflow")
            is_true = ebackup_upgrade.precheck()

            if not is_true:
                logger.error("Precheck by DMK failed.")
                raise FCUException(650036)
            
            logger.info("Begin to get DMK precheck result.")
            is_true = get_dmk_precheck_result(check_results, server_ips, self.param_dict['eBackup_hcp_pwd'],
                                              self.param_dict['eBackup_root_pwd'], self.param_dict['eBackup_Version'])
            if not is_true:
                logger.error("Prechecking is unpassed by DMK.")

            logger.info("Precheck nodes({}) completed.".format(server_ips))
            return Message(200, check_results=check_results)
        except FCUException as e:
            logger.error("Do precheck task on DMK failed.")
            return Message(500, e)
        except Exception as e:
            logger.error("Failed to exec Workflow ,the reason is %s" % e)
            return Message(500, error_msg_cn="升级前检查出现异常，请查看日志并重试",
                           error_msg_en="Exception occurs while prechecking,please check the log and try again.")

    def rollback(self, project_id, pod_id, regionid_list):
        return Message(200)

    def retry(self, project_id, pod_id, regionid_list):
        return self.execute(project_id, pod_id, regionid_list)


class DriverPrecheck(StepBaseInterface):
    def __init__(self, project_id, pod_id, regionid_list):
        super(DriverPrecheck, self).__init__(project_id, pod_id, regionid_list)
        self.project_id = project_id
        self.pod_id = pod_id
        self.regionid_list = regionid_list
        self.region_id = regionid_list[0]
        self.database = BaseOps()
        self.__db_param_dict = Utils.init_system_params(project_id, regionid_list[0])
        self.__ssh = Ssh()

    def _execute_precheck(self, reverse_proxy_ip):
        try:
            version_check_cmds = '''cat /usr/lib/python2.7/site-packages/cinder/backup/drivers/ebackupversion.conf 2>/dev/null || ''' + \
            '''cat /opt/cloud/services/cascading-cinder/venv/lib/python2.7/site-packages/cinder/backup/drivers/ebackupversion.conf 2>/dev/null || ''' + \
            '''cat /usr/lib64/python2.7/site-packages/cinder/backup/drivers/ebackupversion.conf 2>/dev/null'''
            
            driver_host_dict = get_eBackup_Driver_nodes(reverse_proxy_ip, self.__db_param_dict)
            if not driver_host_dict:
                logger.info("eBackup is not supported in the cascaded layer:" + reverse_proxy_ip)
                return True, {}
            driver_ip_array = driver_host_dict["eBackupDriver"]
            login_user = "fsp"
            login_password = self.__db_param_dict['openstack_fsp_pwd']
            root_pwd = self.__db_param_dict['openstack_root_pwd']
            uninstalled_ips = []
            installed_ips = []
            for server_ip in driver_ip_array:
                ssh_client = self.__ssh.ssh_create_client(server_ip, login_user, login_password)
                self.__ssh.ssh_send_command(ssh_client, 'su - root', 'Password:', 100)
                self.__ssh.ssh_send_command(ssh_client, root_pwd, '#', 100)
                result = self.__ssh.ssh_exec_command_return_list(ssh_client, version_check_cmds)
                self.__ssh.ssh_close(ssh_client)
                logger.info("dirver node " + server_ip + " version is " + str(result))

                if -1 == str(result).find('eBackupVersion'):
                    uninstalled_ips.append(server_ip)
                else:
                    installed_ips.append(server_ip)
            file_path = os.path.abspath(__file__ + '/../' + reverse_proxy_ip + '.txt')
            if 0 != len(installed_ips):
                with open(file_path, mode='w') as fp:
                    fp.truncate()
                    # write cps node to file
                    fp.write(','.join(driver_host_dict["cpsnode"]) + '\n')
                    # write driver node to file
                    fp.write(','.join(installed_ips + uninstalled_ips) + '\n')
                    if len(installed_ips) != len(driver_ip_array):
                        return False, {"uninstalled_ips": uninstalled_ips, "all_uninstalled": False}
                    else:
                        return True, {}
            else:
                if os.path.exists(file_path):
                    os.remove(file_path)
                logger.error("eBackup driver is not installed in the cascaded layer:" + reverse_proxy_ip)
                return False, {"uninstalled_ips": uninstalled_ips, "all_uninstalled": True}

        except Exception as ex:
            logger.error(str(ex))
            return False, {"Exception": str(ex)}

    def execute(self, project_id, pod_id, regionid_list):
        # in 8.0.0 it is no need to check if the eBackup driver existed at driver nodes
        # return Message(200, check_results=eBackup_Driver_status_check_SUCCESS)
        region_type = self.database.get_region_type(self.project_id)
        logger.info("The network type is %s" % region_type)
        check_result = []
        if region_type.lower() == "type1":
            try:
                cascaded_reverse_ips = get_cascaded_reverse_ips(self.__db_param_dict)
                if 0 == len(cascaded_reverse_ips):
                    logger.error("Fail to get reverse proxy ips of the cascaded layers.")
                    raise Exception("Fail to get reverse proxy ips of the cascaded layers.")
                partly_uninstall_az = []
                partly_uninstall_nodes = []
                all_uninstall_az = []
                all_uninstall_nodes = []
                for each_reverse_ip in cascaded_reverse_ips:
                    logger.info("Begin to precheck the cascaded layer %s" % each_reverse_ip)
                    is_true, error_msg = self._execute_precheck(each_reverse_ip)
                    if is_true:
                        logger.info("Precheck eBackup driver successfully "
                                    "in the cascaded layer(%s)" % each_reverse_ip)
                    else:
                        logger.error("Fail to precheck eBackup driver "
                                     "in the cascaded layer(%s)" % each_reverse_ip)
                        if 'Exception' in error_msg:
                            driver_check_result = CheckResult(itemname_ch="是否存在未安装eBackup driver的fsp集群",
                                                              itemname_en="If there is no eBackup Driver in this fsp cluster",
                                                              status="failure",
                                                              error_msg_cn=FCUException(650008, error_msg['Exception']))
                            check_result.append(driver_check_result)
                            continue
                        if error_msg['all_uninstalled']:
                            all_uninstall_az.append(each_reverse_ip)
                            all_uninstall_nodes += error_msg["uninstalled_ips"]
                        else:
                            partly_uninstall_az.append(each_reverse_ip)
                            partly_uninstall_nodes += error_msg["uninstalled_ips"]

                if 0 != len(partly_uninstall_az):
                    logger.info("eBackup driver is not installed at some nodes: %s,"
                                "it will be installed during upgrading." % str(partly_uninstall_nodes))

                if 0 != len(all_uninstall_az):
                    driver_check_result = CheckResult(itemname_ch="是否存在未安装eBackup driver的fsp集群",
                                                      itemname_en="If there is no eBackup Driver in this fsp cluster",
                                                      status="failure",
                                                      error_msg_cn=FCUException(650022, ','.join(all_uninstall_az),
                                                                                ",".join(all_uninstall_nodes)))
                    logger.error("eBackup driver is not installed at some nodes:" + str(all_uninstall_nodes))
                else:
                    driver_check_result = CheckResult(itemname_ch="是否存在未安装eBackup driver的fsp集群",
                                                      itemname_en="If there is no eBackup Driver in this fsp cluster",
                                                      status="success")
                    logger.info("eBackup driver is installed in all AZ.")

                check_result.append(driver_check_result)

                return Message(200, check_results=check_result)
            except Exception as ex:
                logger.error(str(ex))
                return Message(500, str(ex), str(ex))
        else:
            try:
                reverse_proxy_ip = self.__db_param_dict['openstack_reverse_proxy_ip']
                if reverse_proxy_ip is None:
                    logger.info("openstack_reverse_proxy_ip is None,eBackup driver precheck skipped...")
                    return Message(200, check_results=eBackup_Driver_status_check_SUCCESS)
                check_result = []
                is_true, error_msg = self._execute_precheck(reverse_proxy_ip)
                if is_true:
                    logger.info("Precheck eBackup driver successfully in the cascaded layer(%s)" % reverse_proxy_ip)
                else:
                    logger.error("Fail to precheck eBackup driver in the cascaded layer(%s)" % reverse_proxy_ip)
                    if 'Exception' in error_msg:
                        driver_check_result = CheckResult(itemname_ch="是否存在未安装eBackup driver的fsp集群",
                                                          itemname_en="If there is no eBackup Driver in this fsp cluster",
                                                          status="failure",
                                                          error_msg_cn=FCUException(650022, error_msg['Exception']))
                        check_result.append(driver_check_result)
                        return Message(200, check_results=check_result)

                    if error_msg['all_uninstalled']:
                        driver_check_result = CheckResult(itemname_ch="是否存在未安装eBackup driver的fsp集群",
                                                          itemname_en="If there is no eBackup Driver in this fsp cluster",
                                                          status="failure",
                                                          error_msg_cn=FCUException(650022, reverse_proxy_ip, ",".join(error_msg["uninstalled_ips"])))

                        logger.error("eBackup driver is not installed at some nodes:" + str(error_msg["uninstalled_ips"]))
                        check_result.append(driver_check_result)
                    else:
                        logger.info("eBackup driver is not installed at some nodes: %s,"
                                    "it will be installed during upgrading." % ",".join(error_msg["uninstalled_ips"]))

                if 0 != len(check_result):
                    logger.error("Fail to precheck eBackup driver in the cascaded layer.")
                    return Message(200, check_results=check_result)

                return Message(200, check_results=eBackup_Driver_status_check_SUCCESS)
            except Exception as ex:
                logger.error(str(ex))
                return Message(500, str(ex), str(ex))

    def rollback(self, project_id, pod_id, regionid_list):
        return Message(200)

    def retry(self, project_id, pod_id, regionid_list):
        return self.execute(project_id, pod_id, regionid_list)