# -*- coding: utf-8 -*-
# Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved.
from tenacity import retry, stop_after_attempt, wait_fixed

import utils.common.log as logger
from utils.common.exception import HCCIException
from utils.business.project_util import ProjectApi
from plugins.DistributedStorage.common.rest_client import StorageSSHClient
from plugins.DistributedStorage.common.parameter_gain import ParamsGain
from plugins.DistributedStorage.Replication.scripts.common_utils.rest_operate import RestOperate
from plugins.DistributedStorage.common.base import TestCase


class QuorumServiceUpgrade(TestCase):
    def __init__(self, project_id, pod_id, fs_args, regionid_list, **kwargs):
        super(QuorumServiceUpgrade, self).__init__(project_id, pod_id)
        self.regionid_list = regionid_list
        self.fs_args = fs_args
        self.more_args = kwargs
        self.quorum_server_user = 'root'
        self.quorum_server_pwd = self.fs_args.get("quorum_server_pwd")
        self.quorum_server_ip = self.fs_args["quorum_server_ip"]
        self.package_file = self.fs_args["package_path"]
        self.package_name = self.fs_args["package_name"]
        self.remote_path = "/root/QuorumServer_tmp"
        self.dm_user = fs_args["user_name"]
        self.dm_pwd = fs_args["password"]
        self.float_ip = fs_args.get("float_ip")
        self.opr = RestOperate(self.float_ip)
        self.suit_info = ProjectApi().get_storage80_info(project_id)
        self.ssh_client = StorageSSHClient(
            self.quorum_server_ip, self.quorum_server_user, self.quorum_server_pwd)
        self.error_code = 621019

    def procedure(self):
        logger.info("Start to update quorum service.")
        if not self.pre_upgrade_check():
            return
        # 上传软件包
        self.upload_package()
        # 升级仲裁软件
        self.update_quorum_service()
        # 升级完成后检查仲裁服务器状态是否为在线
        self.query_quorum_service(self.opr, self.dm_user, self.dm_pwd)

    def pre_upgrade_check(self):
        """
        升级前检查仲裁服务和版本
        :return: bool
        """
        # 登录DM查看当前存储时候有仲裁服务，没有不执行升级
        if not self.query_all_suits_quorum_service():
            logger.warn("The current storage does not have the quorum service.")
            return False
        # 登录仲裁服务器查看当前软件版本，如果版本相同则跳过
        if self.check_service_version():
            logger.warn("The current quorum software version is the same as the target version. No upgrade is required")
            return False
        cmd = "[ -d %s ] && rm -rf %s" % (self.remote_path, self.remote_path)
        self.ssh_client.send_cmd_return(cmd)
        cmd = "mkdir -p %s;echo last=$?" % self.remote_path
        ret_cmd = self.ssh_client.send_cmd_return(cmd)
        if str(ret_cmd).find('last=0') == -1:
            err_msg = "Fail to create remote tmp file path."
            raise Exception(err_msg)
        return True

    def query_all_suits_quorum_service(self):
        """
        双活场景升级顺序，一套升级完成并点击确认后才能升级另外一套，业务存储不能并行升级
        登录当前所有并行升级集群查看是否有存在多套存储包含仲裁服务器，存在报错
        :return:
        """
        logger.info("Query all suits quorum service")
        quorum_service_num = 0
        quorum_service_flag = {
            0: False,
            1: True
        }
        quorum_float = None
        for suit_id, _ in self.suit_info.items():
            cur_fs_arg = ParamsGain(self.project_id, self.pod_id,
                                    self.regionid_list).get_args(suit_id)
            float_ip = cur_fs_arg.get("float_ip")
            current_opt = RestOperate(float_ip)
            user_name = cur_fs_arg.get("user_name")
            pwd = cur_fs_arg.get("password")
            if self.query_quorum_service(current_opt, user_name, pwd):
                if self.float_ip == float_ip:
                    quorum_float = self.float_ip
                quorum_service_num += 1
        if quorum_service_num > 1:
            err_msg = "The CSHA scenario does not support concurrent upgrade of multiple service storage systems."
            logger.error(err_msg)
            raise HCCIException(self.error_code, err_msg)
        return quorum_service_flag.get(quorum_service_num) and quorum_float == self.float_ip

    @retry(stop=stop_after_attempt(3), wait=wait_fixed(60), reraise=True)
    def query_quorum_service(self, opt, username, passwd):
        """
        当前存储有仲裁服务返回True，没有返回False
        :return: bool
        """
        status_code, error_code, error_des = opt.login(
            username, passwd)
        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)
        try:
            result = opt.query_control_cluster()
            control_cluster_id = result.get_control_cluster_id()
            if not control_cluster_id:
                return False
            result = opt.query_quorum_server(control_cluster_id)
            if not result.res.json().get("serviceCmdData"):
                return False
            quorum_server_id, state = result.get_quorum_server_id(self.quorum_server_ip)
            if not quorum_server_id:
                err_msg = 'The quorum server [%s] is not found in the current cluster.' % self.quorum_server_ip
                logger.error(err_msg)
                raise Exception(err_msg)
            if state != "ON_LINE":
                err_msg = "The quorum server status is not ON_LINE, please Check"
                logger.error(err_msg)
                raise Exception(err_msg)
        finally:
            opt.logout()
        return True

    def check_service_version(self):
        """
        当前仲裁服务器版本与目标版本一直返回False，不一致True
        :return: bool
        """
        logger.info("Checking the Arbitration Software Version")
        self.ssh_client.send_cmd("qsadmin", "admin:/>")
        cmd_ret = self.ssh_client.send_cmd("show server_info", "admin:/>")
        logger.info("The arbitration software version is %s." % cmd_ret)
        version = [item.split(':')[1].strip(" ") for item in cmd_ret if "Version" in item][0]
        package = [item.split(':')[1].strip(" ") for item in cmd_ret if "Package" in item][0]
        self.ssh_client.send_cmd("exit", "#")
        return self.package_name in package

    def update_quorum_service(self):
        """
        升级仲裁软件
        :return:
        """
        cmd = '%s/package/quorum_server.sh -%s' % (self.remote_path, "upgrade")
        ret_cmd = self.ssh_client.send_cmd_return(cmd, timeout=600)
        if str(ret_cmd).find("QuorumServer upgrade success completed") == -1:
            err_msg = "Failed to upgrade QuorumServer, detail:%s" % str(ret_cmd)
            raise Exception(err_msg)
        logger.info("QuorumServer upgrade success completed")

    def upload_package(self):
        """
        上传升级软件包至根目录
        :return:
        """
        logger.info("Upload quorum service package to quorum server")
        self.ssh_client.upload(self.package_file, self.remote_path)
        cmd = 'cd %s' % self.remote_path
        self.ssh_client.send_cmd(cmd, "#")
        cmd = 'tar -zxf %s && cd package/ && chmod 500 ./*;echo last=$?' % self.package_name
        ret_cmd = self.ssh_client.send_cmd_return(cmd, timeout=120)
        if str(ret_cmd).find("last=0") == -1:
            err_msg = 'Failed to decompress the file %s.' % self.package_name
            raise Exception(err_msg)
