# -*- coding: utf-8 -*-
import time
import traceback

import utils.common.log as logger
from utils.common.exception import HCCIException
from plugins.DistributedStorage.common.UpgradeOperate import UpgradeOperate
from plugins.DistributedStorage.common.UpgradeHotPatchOperate import UpgradeHotPatchOperate
from plugins.DistributedStorage.common.base import TestCase
from plugins.DistributedStorage.common.PublicHandleNew import RestPublicMethod
from plugins.DistributedStorage.common.RestClient import StorageSSHClient
from plugins.DistributedStorage.common.constants import HotpatchStates
from plugins.DistributedStorage.Upgrade.scripts.impl.TC_Pre_Upgrade_Check import \
    PreUpgradeCheck
from plugins.DistributedStorage.Upgrade.scripts.impl.TC_Upgrade_Pkg import \
    UpgradePkg
from plugins.DistributedStorage.Upgrade.scripts.impl.TC_Distributed_Pkg import \
    DistributePkg


class HotpatchUpgradePkg(TestCase):
    def __init__(self, project_id, pod_id, fs_args, condition=None,
                 metadata=None, **kwargs):
        super(HotpatchUpgradePkg, self).__init__(project_id, pod_id)
        self.project_id = project_id
        self.pod_id = pod_id
        self.fs_args = fs_args
        self.fs_args["upgrade_mode"] = 1
        self.node_list = list()
        self.master_node = fs_args.get("master_node")
        self.slaver_node = fs_args.get("slaver_node")
        self.region_id = fs_args.get("region_id")
        self.user_name = fs_args["user_name"]
        self.password = fs_args["password"]
        self.hotpatch_state_key = fs_args.get("hotpatch_upgrade_key")
        self.master_client = None
        self.slaver_client = None
        self.remote_path = "/tmp/upgrade_tmp_hotpatch"
        self.opr = UpgradeOperate(fs_args)
        self.rest_opr = RestPublicMethod(project_id, pod_id, fs_args)

    def procedure(self):
        logger.info('Start upgrade task.')
        try:
            status_code, error_code, error_des = self.opr.try_login(self.user_name, self.password)
            if status_code != 200 or error_code != 0:
                err_msg = "Failed to login, Detail:[status:%s,code:%s]%s" % (status_code, error_code, error_des)
                logger.error(err_msg)
                raise Exception(err_msg)
            self.upgrade_hotpatch_procedure()
        except HCCIException as e:
            logger.error('upgrade pkg failed:{}'.format(e))
            logger.error(traceback.format_exc())
            raise e
        except Exception as e:
            logger.error('upgrade pkg failed:{}'.format(e))
            logger.error(traceback.format_exc())
            raise HCCIException(620009, str(e))
        finally:
            if self.fs_args.get("hot_patch_tag"):
                self.del_script_om_fsm()

    def retry(self):
        logger.info('Start retry upgrade task.')
        try:
            status_code, error_code, error_des = self.opr.try_login(self.user_name, self.password)
            if status_code != 200 or error_code != 0:
                err_msg = "Failed to login, Detail:[status:{},code:{}]{}".format(status_code, error_code, error_des)
                logger.error(err_msg)
                raise Exception(err_msg)
            #  热补丁升级场景重试流程
            self.hotpatch_upgrade_retry()

        except HCCIException as e:
            logger.error('retry upgrade pkg failed:{}'.format(e))
            logger.error(traceback.format_exc())
            raise e
        except Exception as e:
            logger.error('retry upgrade pkg failed:{}'.format(e))
            logger.error(traceback.format_exc())
            raise HCCIException(620009, str(e))
        finally:
            if self.fs_args.get("hot_patch_tag"):
                self.del_script_om_fsm()

    def upgrade_hotpatch_procedure(self):
        # 获取主备节点
        self.create_fsm_client()
        # 上传脚本到主备fsm节点
        self.upload_script_to_fsm()
        upgrade_tasks = [
            "distribute_pkg",
            "pre_upgrade_check",
            "product_upgrade",
            "backup_db_data"
        ]
        state = self.get_upgrade_state()
        while state <= HotpatchStates.BACKUP_HOTPATCH_DB_START:
            self.update_upgrade_state(state)
            getattr(self, upgrade_tasks[state])()
            state += 1

    def hotpatch_upgrade_retry(self):
        """
        热补丁+大包升级场景重试流程
        """
        # 获取主备节点
        self.create_fsm_client()
        # 上传脚本到主备fsm节点
        self.upload_script_to_fsm()
        upgrade_tasks = [
            "distribute_pkg",
            "pre_upgrade_check",
            "product_upgrade",
            "backup_db_data"
        ]
        # 获取失败步骤
        state = self.get_upgrade_state()
        if state == HotpatchStates.HOTPATCH_UPGRADE_START:
            # 热补丁升级失败走升级重试步骤
            upgrade_tasks[2] = "product_upgrade_retry"
        while state <= HotpatchStates.BACKUP_HOTPATCH_DB_START:
            self.update_upgrade_state(state)
            getattr(self, upgrade_tasks[state])()
            state += 1

    def product_upgrade(self):
        """
        存储大包升级
        """
        UpgradePkg(self.project_id, self.pod_id, self.fs_args).procedure()

    def product_upgrade_retry(self):
        UpgradePkg(self.project_id, self.pod_id, self.fs_args).retry()

    def pre_upgrade_check(self):
        """
        升级前检查
        """
        PreUpgradeCheck(self.project_id, self.pod_id, self.fs_args).procedure()

    def distribute_pkg(self):
        """
        软件包分发
        """
        DistributePkg(self.project_id, self.pod_id, self.fs_args).procedure()

    def upload_script_to_fsm(self):
        """
        上传脚本至fsm主备节点
        """
        node_list = [(self.master_client, self.master_node),
                     (self.slaver_client, self.slaver_node)]
        for ssh_client, node in node_list:
            UpgradeHotPatchOperate.upload_script_to_fsm(ssh_client, node, self.remote_path)

    def del_script_om_fsm(self):
        """
        删除fsm节点上的脚本文件
        """
        client_list = [client for client in
                       [self.master_client, self.slaver_client] if client]
        for ssh_client in client_list:
            UpgradeHotPatchOperate.del_script_om_fsm(ssh_client, self.remote_path)
            del ssh_client

    def create_fsm_client(self):
        """
        获取当前主节点
        """
        self.master_client = StorageSSHClient(*self.master_node[:3])
        self.master_client.switch_root(self.master_node.root_pwd)
        self.slaver_client = StorageSSHClient(*self.slaver_node[:3])
        self.slaver_client.switch_root(self.slaver_node.root_pwd)

    def backup_db_data(self, step="hotpatch"):
        """
        备份主备fsm数据库
        step: hotpatch:备份热补丁数据库
        step: product:备份产品大包数据
        """
        logger.info("Back %s data start." % step)
        for ssh_client in [self.master_client, self.slaver_client]:
            UpgradeHotPatchOperate.backup_db_data(ssh_client, self.remote_path, step=step)
        logger.info("Back %s data success." % step)

    def update_upgrade_state(self, state=0):
        """
        更新记录当前升级步骤
        0：上传补丁包开始
        1：补丁包升级前检查开始
        2：补丁升级开始
        3：部分补丁数据库开始
        4：备份补丁软件仓开始
        """
        UpgradeHotPatchOperate.update_operate_state(self.project_id, self.region_id,
                                                    self.hotpatch_state_key, state=state)

    def get_upgrade_state(self):
        return UpgradeHotPatchOperate.get_operate_state(self.project_id, self.region_id,
                                                        self.hotpatch_state_key)
