# -*- coding: utf-8 -*-
# Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved.
"""分布式存储一跳升级场景：deploymanager热补丁升级，同时分发软件包"""

import pathlib
import traceback

import utils.common.log as logger
from utils.common.exception import HCCIException
from utils.common.message import Message
from utils.common.ssh_util import Ssh
from utils.common.fic_base import StepBaseInterface
from utils.common.software_package_util import find_software_package
from plugins.DistributedStorage.common.base import TestCase
from plugins.DistributedStorage.common.parameter_gain import ParamsGain
from plugins.DistributedStorage.logic.install_operate import InstallOperate
from plugins.DistributedStorage.utils.common.deploy_constant import DeployConstant


class InstallDeploymanagerPatchInf(StepBaseInterface):
    def __init__(self, project_id, pod_id, regionid_list=None, suit_id=None):
        super(InstallDeploymanagerPatchInf, self).__init__(project_id, pod_id, regionid_list)
        self.project_id = project_id
        self.pod_id = pod_id
        self.regionid_list = regionid_list
        self.suit_id = suit_id
        self.fs_args = ParamsGain(project_id, pod_id, regionid_list).get_args(suit_id)
        self.install_deploymanager_pkg = InstallDeploymanagerPatchImp(self.project_id, self.pod_id, self.fs_args)

    def execute(self, project_id, pod_id, regionid_list=None, suit_id=None):
        logger.info('Start install Deploymanager Package')
        try:
            self.install_deploymanager_pkg.procedure()
        except Exception as err:
            logger.error("Install Deploymanager Package error:{}".format(traceback.format_exc()))
            return Message(500, str(err))
        return Message()

    def rollback(self, project_id, pod_id, regionid_list=None, suit_id=None):
        """
        标准调用接口：执行回滚
        :param project_id:
        :param pod_id:
        :return:Message类对象
        """
        return Message()

    def retry(self, project_id, pod_id, regionid_list=None, suit_id=None):
        """
        标准调用接口：重试
        :return: Message类对象
        """
        return self.execute(self.project_id, self.pod_id, self.regionid_list, self.suit_id)


class InstallDeploymanagerPatchImp(TestCase):
    def __init__(self, project_id, pod_id, fs_args, condition=None, metadata=None, **kwargs):
        super(InstallDeploymanagerPatchImp, self).__init__(project_id, pod_id)
        self.condition = condition
        self.metadata = metadata
        self.fs_args = fs_args
        self.more_args = kwargs
        self.admin_pwd = fs_args.get("password")
        self.master_ip = self.fs_args.get("master_ip")
        self.master_username = self.fs_args.get("master_username")
        self.master_password = self.fs_args.get("master_password")
        self.master_root_pwd = self.fs_args.get("master_root_pwd")
        self.slaver_ip = self.fs_args.get("slaver_ip")
        self.slaver_username = self.fs_args.get("slaver_username")
        self.slaver_password = self.fs_args.get("slaver_password")
        self.slaver_root_pwd = self.fs_args.get("slaver_root_pwd")
        self.master_client, self.slaver_client = None, None
        self.standby_client = None
        self.active_node, self.standby_node = None, None
        self.client_list = []
        self.error_code = 621022
        self.patch_pkg, self.patch_pkg_dir = "", ""

    def procedure(self):
        self.patch_pkg, self.patch_pkg_dir = self.get_patch_pkg_name_and_dir()
        try:
            logger.info("step1. Log in to the management nodes")
            self.ssh_mgmt_nodes()
            logger.info("step2. Querying the Standby Node")
            self.get_standby_node()
            logger.info("step3. Decompress the {} package on the standby node".format(self.patch_pkg))
            self.unzip_pkg_dir()
            logger.info("step4. Run the installation script on the standby node")
            try:
                self.upgrade_deploymanager_patch()
            except Exception as err:
                logger.error("Install deploymanager package failed:{}".format(err))
                raise HCCIException(self.error_code, err, self.standby_node[0]) from err
            logger.info("Succeeded in performing the upgrade")
        finally:
            for client in self.client_list:
                Ssh.ssh_close(client)

    def ssh_mgmt_nodes(self):
        self.master_client = InstallOperate.create_ssh_root_client(
            self.master_ip, self.master_username, self.master_password, self.master_root_pwd)
        self.client_list.append(self.master_client)
        self.slaver_client = InstallOperate.create_ssh_root_client(
            self.slaver_ip, self.slaver_username, self.slaver_password, self.slaver_root_pwd)
        self.client_list.append(self.slaver_client)

    def get_standby_node(self):
        logger.info("Start to Querying the Standby Node")
        cmd = "if [ -e /root/{} ];then echo pkg_exist;fi".format(self.patch_pkg)
        ret = Ssh.ssh_exec_command_return(self.master_client, cmd)
        if str(ret).__contains__("pkg_exist"):
            logger.info("The Standby node ip is {}".format(self.master_ip))
            self.standby_client = self.master_client
            self.standby_node = [self.master_ip, self.master_username, self.master_password, self.master_root_pwd]
            self.active_node = [self.slaver_ip, self.slaver_username, self.slaver_password, self.slaver_root_pwd]
            return
        ret = Ssh.ssh_exec_command_return(self.slaver_client, cmd)
        if not str(ret).__contains__("pkg_exist"):
            err_msg = "The {} does not exist in the /root directory " \
                      "on the nodes{}".format(self.patch_pkg, [self.master_ip, self.slaver_ip])
            logger.error(err_msg)
            raise Exception(err_msg)
        logger.info("The Standby node ip is {}".format(self.slaver_ip))
        self.standby_client = self.slaver_client
        self.standby_node = [self.slaver_ip, self.slaver_username, self.slaver_password, self.slaver_root_pwd]
        self.active_node = [self.master_ip, self.master_username, self.master_password, self.master_root_pwd]

    def unzip_pkg_dir(self):
        unzip_dir_name = self.patch_pkg.strip(".tar.gz")
        cmd = "echo -e 'A' | tar -zxf /root/{} -C /root/ && " \
              "cd /root/{}/deploymanager && echo last_result=$?".format(self.patch_pkg, unzip_dir_name)
        ret = Ssh.ssh_exec_command_return(self.standby_client, cmd)
        if not str(ret).__contains__("last_result=0"):
            err_msg = "Unzip {} failed, node ip:{}, result：{}".format(self.patch_pkg, self.slaver_ip, ret)
            logger.error(err_msg)
            raise Exception(err_msg)
        cmd = "DP_PKG=$(ls OceanStor-Pacific_deploymanager_`uname -p`*.tar.gz);\\cp -f ${DP_PKG} /root;" \
              "echo -e 'A' | tar -zxf ${DP_PKG} -C /root && cd /root/${DP_PKG%.tar.gz}/action && whoami"
        ret = Ssh.ssh_exec_command_return(self.standby_client, cmd)
        if not str(ret).__contains__("root"):
            err_msg = "Unzip OceanStor-Pacific_deploymanager*.tar.gz failed, " \
                      "node ip:{}, result：{}".format(self.slaver_ip, ret)
            logger.error(err_msg)
            raise Exception(err_msg)
        if not unzip_dir_name:
            logger.warn("The package name is empty:{}".format(unzip_dir_name))
            return
        cmd = "rm -rf /root/{}".format(unzip_dir_name)
        Ssh.ssh_send_command(self.standby_client, cmd, "#", 20, 3)
        logger.info("Decompressing the {} package succeeded.".format(self.patch_pkg))

    def upgrade_deploymanager_patch(self):
        """
        deploymanager热补丁升级，deploymanager内部自动完成软件包分发
        :return:
        """
        logger.info("start to install deploymanager package")
        cmd = "bash upgrade.sh"
        ret = Ssh.ssh_send_command(self.standby_client, cmd, "(yes/no)", 20, 3)
        logger.info("input [{}] cmd result:{}".format(cmd, ret))
        ret = Ssh.ssh_send_command(self.standby_client, "yes", "username", 20, 3)
        logger.info("input yes cmd result:{}".format(ret))
        ret = Ssh.ssh_send_command(self.standby_client, DeployConstant.DM_LOGIN_USER, "admin password", 20, 3)
        logger.info("input admin user result:{}".format(str(ret).replace("password", "***")))
        ret = Ssh.ssh_send_command(self.standby_client, self.admin_pwd, "remote username", 60, 3)
        logger.info("Authentication admin user result:{}".format(ret))
        ret = Ssh.ssh_send_command(self.standby_client, DeployConstant.FSM_USER, "fsadmin password", 20, 3)
        logger.info("Input fsadmin user result:{}".format(str(ret).replace("password", "***")))
        ret = Ssh.ssh_send_command(self.standby_client, self.active_node[2], "root password", 20, 3)
        logger.info("Authentication fsadmin user result:{}".format(str(ret).replace("password", "***")))
        Ssh.ssh_send_command(self.standby_client, self.active_node[3], "Succeeded in performing the upgrade", 3600, 3)
        logger.info("Succeeded in performing the upgrade")

    def get_patch_pkg_name_and_dir(self):
        pkg_dict, num = find_software_package(DeployConstant.ONE_STEP_UPGRADE.get("hot_pkg"), self.project_id)
        if not pkg_dict:
            err_msg = "The {} does not exist in the /home/pkg directory, " \
                      "result:{}".format(DeployConstant.ONE_STEP_UPGRADE.get("hot_pkg"), pkg_dict)
            logger.error(err_msg)
            raise Exception(err_msg)
        patch_pkg = pathlib.Path(list(pkg_dict.keys())[0])
        patch_pkg_dir = pathlib.Path(patch_pkg.stem).stem
        logger.info("Patch pkg: {}".format(patch_pkg))
        return str(patch_pkg), patch_pkg_dir
