# -*- coding:utf-8 -*-
import os
from utils.common.message import Message
import utils.common.log as logger
from utils.common.ssh_util import Ssh
from plugins.eBackup.common.dmkTask import DMKTask
from utils.common.fic_base import StepBaseInterface
from plugins.eBackup.common.util import Utils, precheck_ebackup, check_access_status, g_check_item
from utils.common.exception import FCUException
from platforms.upgradecheck.check_result import CheckResult


class EbackupPatchTool(object):
    def __init__(self, host_ips, db_param_dict, ebackup_type):
        self.param_dict = db_param_dict
        self.ebackup_type = ebackup_type
        self.host_ips = host_ips
        self.dmk_task = DMKTask(self.param_dict['dmk_floatIp'], self.param_dict['eBackup_dmk_user'],
                                self.param_dict['eBackup_dmk_password'])
    
    def precheck(self, check_results):
        # 1.check acess status
        check_nodes = self.param_dict['eBackup_Datamover_nodes'] if self.ebackup_type == 'datamover' \
            else self.param_dict['eBackup_Workflow_nodes']
        for group in check_nodes.split('|'):
            logger.info("Begin to check access status of the nodes:" + str(group))
            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 for nodes:" + str(group))
                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)
        # 2.check env
        logger.info("Begin to do precheck...")
        return precheck_ebackup(check_results, self.host_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'])
         
    def patch(self):
        is_true = self.is_all_patched()
        if is_true:
            logger.info("All nodes are patched.")
            return True
        return self.patch_force()

    def patch_force(self):
        return self.deploy_with_dmk("Upgrade")

    def rollback(self):
        is_true = self.is_all_rollbacked()
        if is_true:
            logger.info("All nodes are rollbacked.")
            return True
        return self.rollback_force()

    def rollback_force(self):
        return self.deploy_with_dmk("Rollback")

    def is_all_patched(self):
        logger.info("Begin to check whether all node are patched.")
        for ip in self.host_ips:
            if not self.is_patched(ip):
                logger.info("There some nodes are not patched.")
                return False
        logger.info("All nodes are patched.")
        return True

    def is_all_rollbacked(self):
        logger.info("Begin to check whether all node are rollbacked.")
        for ip in self.host_ips:
            if self.is_patched(ip):
                logger.info("There some nodes are not rollbacked.")
                return False
        logger.info("All nodes are rollbacked.")
        return True

    def is_patched(self, ip):
        ssh = Ssh()
        ssh_client = None
        check_patch_cmd = '''grep "Version:" /opt/huawei-data-protection/ebackup/tmp/patch_*.info | grep -w %s | awk -F "[ |:]" '{print $NF}' ''' % self.param_dict["eBackup_Version"]
        logger.info("Begin to check patch version.")
        try:
            ssh_client = ssh.ssh_create_client(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)
            result = ssh.ssh_exec_command_return_list(ssh_client, check_patch_cmd)
            patch_version = "No patch" if len(result) == 0 else result[0].strip().replace('\n', '')
            logger.info("The patch version is {0} at node {1}".format(patch_version, ip))
            return patch_version == self.param_dict["eBackup_Version"]
        except Exception as e:
            logger.error("Exception occurs when check whether all node are patched: " + str(e))
            raise e
        finally:
            Utils.close_ssh_clinet(ssh_client)

    def deploy_with_dmk(self, action):
        #ebackup_config, ebackup_host = self.get_all_params()
        ebackup_config = ""
        ebackup_host = "[eBackupService]\n" + '\n'.join(self.host_ips)
        ebackup_action = '[{0}] {1} eBackup Patch'.format(action, action)
        result = self.dmk_task.do_task(self.param_dict["eBackup_Version"], ebackup_action,
                                       ebackup_host, ebackup_config, "hcp", 'eBackupSoftware_Patch')
        if not result:
            logger.error("Do DMK task %s failed." % ebackup_action)

        return result


class DatamoverPatch(StepBaseInterface):
    def __init__(self, project_id, pod_id, regionid_list):
        self.project_id = project_id
        self.pod_id = pod_id
        self.regionid_list = regionid_list
        self.param_dict = Utils.init_system_params(project_id, regionid_list[0])
        self.result_file = os.path.abspath(__file__ + '/../{}_datamover_patch_result.txt'.format(regionid_list[0]))

    def execute(self, project_id, pod_id, regionid_list):
        try:
            host_info = self.param_dict["eBackup_Datamover_nodes"]
            host_info = host_info.replace(" ", "").split("|")

            all_result = []
            with open(self.result_file, mode='w') as fp:
                fp.truncate()
            logger.info("Begin to upgrade all datamover nodes(%s)" % str(host_info))
            for group in host_info:
                host_ips = group.split(";")
                logger.info("Begin to upgrade datamover nodes(%s)" % str(host_ips))
                patch_tool = EbackupPatchTool(host_ips, self.param_dict, "datamover")
                is_true = patch_tool.patch()
                if is_true:
                    logger.info("Upgrade eBackup datamover(%s) successfully." % str(host_ips))
                else:
                    with open(self.result_file, mode='a') as fp:
                        fp.write(','.join(host_ips) + '\n')
                    logger.error("Fail to upgrade eBackup datamover(%s)." % str(host_ips))
                all_result.append(is_true)

            if False in all_result:
                logger.error("Fail to upgrade all eBackup datamover nodes.")
                return Message(500, error_msg_cn="升级Datamover补丁失败，请登录DMK查看失败原因，请勿直接重试",
                               error_msg_en="Upgrade Datamover patch failed, please log in DMK to see the details,"
                                            " do not directly retry")

            logger.info("Upgrade all eBackup datamover successfully.")
            if os.path.exists(self.result_file):
                os.remove(self.result_file)
            return Message(200)
        except FCUException as ex:
            logger.error(str(ex))
            return Message(500, ex)
        except Exception as ex:
            logger.error(str(ex))
            return Message(500, error_msg_cn="升级Datamover补丁出现异常，请联系华为技术工程师",
                           error_msg_en="Exception occurs when retry to upgrade eBackup Datamover patch,"
                                        "please contact huawei technical engineers")

    def retry(self, project_id, pod_id, regionid_list):
        try:
            if not os.path.exists(self.result_file):
                logger.error("There is no result file:" + self.result_file)
                raise FCUException(650032, self.result_file + " does not exist", self.result_file)

            with open(self.result_file, mode='r') as fp:
                host_group_list = fp.readlines()

            if 0 == len(host_group_list):
                logger.error("Get ips from {} failed.".format(self.result_file))
                raise FCUException(650032, "There is no IP address of the node which need to be retried in "
                                   + self.result_file, self.result_file)

            for group in host_group_list:
                if 0 == len(group.replace('\n', '')):
                    logger.info("There is no host.")
                    continue
                host_ips = group.replace('\n', '').split(",")   
                logger.info("Begin to rollback {} force.".format(str(host_ips)))
                patch_tool = EbackupPatchTool(host_ips, self.param_dict, "datamover")
                is_true = patch_tool.rollback_force()
                if not is_true:
                    logger.error("Rollback %s failed." % str(group))
                    return Message(500, error_msg_cn="回退Datamover[%s]失败，请联系华为技术工程师" % str(group),
                                   error_msg_en="Rollback eBackup Datamover[%s]failed,"
                                                "please contact huawei technical engineers." % str(group))

            return self.execute(project_id, pod_id, regionid_list)
        except FCUException as ex:
            logger.error("Exception occurs when retry to upgrade eBackup: " + str(ex))
            return Message(500, ex)
        except Exception as e:
            logger.error("Exception occurs when retry to upgrade eBackup Datamover: " + str(e))
            return Message(500, error_msg_cn="重试出现异常，请联系华为技术工程师",
                           error_msg_en="Exception occurs when retry to upgrade eBackup Datamover patch,"
                                        "please contact huawei technical engineers")


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

    def execute(self, project_id, pod_id, regionid_list):
        try:
            host_ips = self.param_dict["eBackup_Workflow_nodes"].split(";")
            logger.info("Begin to upgrade all workflow nodes(%s)" % str(host_ips))

            patch_tool = EbackupPatchTool(host_ips, self.param_dict, "workflow")
            is_true = patch_tool.patch()
            if not is_true:
                logger.error("Patch {} failed.".format(str(host_ips)))
                return Message(500, error_msg_cn="升级workflow补丁失败，请登录DMK查看失败原因，请勿直接重试",
                               error_msg_en="Upgrade workflow patch failed, please log in DMK to see the details,"
                                            "do not directly retry")
            logger.info("Upgrade eBackup datamover(%s) successfully." % str(host_ips))
            return Message(200)
        except FCUException as ex:
            logger.error(str(ex))
            return Message(500, ex)
        except Exception as ex:
            logger.error(str(ex))
            return Message(500, error_msg_cn="升级workflow补丁出现异常，请联系华为技术工程师",
                           error_msg_en="Exception occurs when upgrade eBackup workflow,"
                                        "please contact huawei technical engineers")

    def retry(self, project_id, pod_id, regionid_list):
        try:

            host_ips = self.param_dict["eBackup_Workflow_nodes"].split(";")
            logger.info("Begin to upgrade all workflow nodes(%s)" % str(host_ips))
            patch_tool = EbackupPatchTool(host_ips, self.param_dict, "workflow")
            is_true = patch_tool.rollback_force()
            if not is_true:
                logger.error("Rollback workflow %s failed." % str(host_ips))
                return Message(500, error_msg_cn="workflow[%s]失败，请联系华为技术工程师" % str(host_ips),
                               error_msg_en="Rollback eBackup workflow[%s]failed,"
                                            "please contact huawei technical engineers." % str(host_ips))

            return self.execute(project_id, pod_id, regionid_list)
        except Exception as e:
            logger.error("Exception occurs when retry to upgrade eBackup workflow: " + str(e))
            return Message(500, error_msg_cn="重试出现异常，请联系华为技术工程师",
                           error_msg_en="Exception occurs when retry to upgrade eBackup workflow,"
                                        "please contact huawei technical engineers")


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

    def execute(self, project_id, pod_id, regionid_list):
        try:
            host_ips = self.param_dict["eBackup_Workflow_nodes"].split(";")
            logger.info("Begin to rollback all workflow patch nodes(%s)" % str(host_ips))

            patch_tool = EbackupPatchTool(host_ips, self.param_dict, "workflow")
            is_true = patch_tool.rollback_force()
            if not is_true:
                logger.error("Rollback patch {} failed.".format(str(host_ips)))
                return Message(500, error_msg_cn="回滚workflow补丁失败，请登录DMK查看失败原因，请勿直接重试",
                               error_msg_en="Rollback workflow patch failed, please log in DMK to see the details,"
                                            "do not directly retry")
            logger.info("Rollback eBackup datamover(%s) patch successfully." % str(host_ips))
            return Message(200)
        except FCUException as ex:
            logger.error(str(ex))
            return Message(500, ex)
        except Exception as ex:
            logger.error(str(ex))
            return Message(500, ex, ex)

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


class DatamoverPatchRollback(StepBaseInterface):
    def __init__(self, project_id, pod_id, regionid_list):
        self.project_id = project_id
        self.pod_id = pod_id
        self.regionid_list = regionid_list
        self.param_dict = Utils.init_system_params(project_id, regionid_list[0])
        self.result_file = os.path.abspath(__file__ + '/../{}_datamover_rollback_result.txt'.format(regionid_list[0]))
    
    def execute(self, project_id, pod_id, regionid_list):
        try:
            host_info = self.param_dict["eBackup_Datamover_nodes"]
            host_info = host_info.replace(" ", "").split("|")

            all_result = []
            with open(self.result_file, mode='w') as fp:
                fp.truncate()
            logger.info("Begin to rollback all datamover nodes(%s)" % str(host_info))
            for group in host_info:
                host_ips = group.split(";")
                logger.info("Begin to rollback datamover nodes(%s)" % str(host_ips))
                patch_tool = EbackupPatchTool(host_ips, self.param_dict, "datamover")
                is_true = patch_tool.rollback()
                if is_true:
                    logger.info("Rollback eBackup datamover(%s) successfully." % str(host_ips))
                else:
                    with open(self.result_file, mode='a') as fp:
                        fp.write(','.join(host_ips) + '\n')
                    logger.error("Fail to rollback eBackup datamover(%s)." % str(host_ips))
                all_result.append(is_true)

            if False in all_result:
                logger.error("Fail to rollback all eBackup datamover nodes.")
                return Message(500, error_msg_cn="回退Datamover补丁失败，请登录DMK查看失败原因，请勿直接重试",
                               error_msg_en="Rollback Datamover patch failed, please log in DMK to see the details,"
                                            "do not directly retry")

            logger.info("Rollback all eBackup datamover successfully.")
            if os.path.exists(self.result_file):
                os.remove(self.result_file)
            return Message(200)
        except FCUException as ex:
            logger.error(str(ex))
            return Message(500, ex)
        except Exception as ex:
            logger.error(str(ex))
            return Message(500, error_msg_cn="回退Datamover补丁出现异常，请联系华为技术工程师",
                           error_msg_en="Exception occurs when retry to rollback eBackup patch,"
                                        "please contact huawei technical engineers")

    def retry(self, project_id, pod_id, regionid_list):
        try:
            if not os.path.exists(self.result_file):
                logger.error("There is no result file:" + self.result_file)
                raise FCUException(650032, self.result_file + " does not exist", self.result_file)

            with open(self.result_file, mode='r') as fp:
                host_group_list = fp.readlines()

            if 0 == len(host_group_list):
                logger.error("Get ips from {} failed.".format(self.result_file))
                raise FCUException(650032, "There is no IP address of the node which need to be retried in "
                                   + self.result_file, self.result_file)
            
            all_result = []
            with open(self.result_file, mode='w') as fp:
                fp.truncate()
            for group in host_group_list:
                if 0 == len(group.replace('\n', '')):
                    logger.info("There is no host.")
                    continue
                host_ips = group.replace('\n', '').split(",")   
                logger.info("Begin to rollback {} force.".format(str(host_ips)))
                patch_tool = EbackupPatchTool(host_ips, self.param_dict, "datamover")
                is_true = patch_tool.rollback_force()
                if not is_true:
                    with open(self.result_file, mode='a') as fp:
                        fp.write(','.join(host_ips) + '\n')
                    logger.error("Rollback patch failed on {}.".format(str(host_ips)))
                else:
                    logger.info("Rollback {} force successfully.".format(str(host_ips)))
                all_result.append(is_true)
            if False in all_result:
                logger.error("Fail to rollback all eBackup datamover nodes.")
                return Message(500, error_msg_cn="回退Datamover补丁失败，请登录DMK查看失败原因，请勿直接重试",
                               error_msg_en="Rollback Datamover patch failed, please log in DMK to see the details,"
                                            "do not directly retry")
            logger.info("Rollback patch on all datamover nodes successfully.")
            if os.path.exists(self.result_file):
                os.remove(self.result_file)
            return Message(200)

        except FCUException as ex:
            logger.error(str(ex))
            return Message(500, ex)
        except Exception as ex:
            logger.error(str(ex))
            return Message(500, error_msg_cn="重试出现异常，请联系华为技术工程师",
                           error_msg_en="Exception occurs when retry to rollback eBackup patch,"
                                        "please contact huawei technical engineers")
