# -*- coding: utf-8 -*-
import string
import os
import shutil
import random
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.base import TestCase
from plugins.DistributedStorage.common.RestClient import StorageSSHClient
from plugins.DistributedStorage.common.constants import ErrorInfo
from plugins.DistributedStorage.common.PublicHandleNew import SystemHandle
from plugins.DistributedStorage.common.PublicHandleNew import SshPublicMethod


class CloudaSelfUpgrade(TestCase):
    def __init__(self, project_id, pod_id, fs_args, condition=None, metadata=None, **kwargs):
        super(CloudaSelfUpgrade, self).__init__(project_id, pod_id)
        self.condition = condition
        self.fs_args = fs_args
        self.metadata = metadata
        self.more_args = kwargs
        self.opr = UpgradeOperate(fs_args)
        self.sys_opr = SystemHandle()
        self.master_ip = fs_args.get("master_ip")
        self.slaver_ip = fs_args.get("slaver_ip")
        self.float_ip = fs_args.get("float_ip")
        self.user_name = fs_args.get("user_name")
        self.password = fs_args.get("password")
        self.slaver_username = fs_args.get("slaver_username")
        self.slaver_password = fs_args.get("slaver_password")
        self.slaver_root_pwd = fs_args.get("slaver_root_pwd")
        self.master_username = fs_args.get("master_username")
        self.master_password = fs_args.get("master_password")
        self.master_root_pwd = fs_args.get("master_root_pwd")
        self.package_name = fs_args.get("package_name")
        self.package_file = fs_args.get("package_path")
        self.tmp_path_suffix = ''.join(random.choices(string.digits + string.ascii_letters, k=10))
        if len(self.package_file) > 60:
            local_dst_base_dir = 'c:\\self_upgrade_tmp'
        else:
            local_dst_base_dir = os.path.splitext(self.package_file)[0]
        self.local_dst_dir = local_dst_base_dir + self.tmp_path_suffix
        self.local_pkg_dir = os.path.join(
            self.local_dst_dir,
            os.path.splitext(os.path.splitext(self.package_name)[0])[0],
            "deploymanager")
        self.remote_pkg_dir_remote = "/home/self_upgrade_tmp" + self.tmp_path_suffix
        self.single_mode = False
        self.upgrade_mode = ""

    def procedure(self):
        logger.info('Start self upgrade task.')
        try:
            self.sys_opr.unzip_file(self.package_file, self.local_dst_dir)
            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 deploy manager, Details:[status:%s,code:%s], error:%s" \
                          % (status_code, error_code, error_des)
                logger.error(err_msg)
                raise HCCIException(621001, err_msg)

            nodes_list = []
            ret_result, ret_data = self.opr.get_servers()
            if ret_result["code"] != 0:
                err_msg = "get servers failed, Detail:[result:%s, data:%s]"\
                          % (ret_result, ret_data)
                logger.error(err_msg)
                raise HCCIException(621003, err_msg)
            for item in ret_data:
                nodes_list.append(item["management_ip"])

            if self.sys_opr.check_pkg_version(self.fs_args) != 80:
                logger.info("current version is not 8.1, not upgrade clouda")
                return

            ret_value = self._try_clouda_self_upgrade(
                self.master_ip, self.master_username, self.master_password,
                self.master_root_pwd, nodes_list)
            if ret_value == ErrorInfo.ERROR_IS_STANDBY:
                ret_value = self._try_clouda_self_upgrade(
                    self.slaver_ip, self.slaver_username, self.slaver_password,
                    self.slaver_root_pwd, nodes_list)
                if ret_value == ErrorInfo.ERROR_IS_STANDBY:
                    err_msg = "Node {}  and Node {} are the slaver " \
                              "node.".format(self.master_ip, self.slaver_ip)
                    raise HCCIException(621006, err_msg)
        except HCCIException as e:
            logger.error('clouda self upgrade failed,details:{}'.format(e))
            logger.error(traceback.format_exc())
            raise e
        except Exception as e:
            logger.error('clouda self upgrade failed,details:{}'.format(e))
            logger.error(traceback.format_exc())
            raise HCCIException(621003, str(e))
        finally:
            logger.info('delete destination dir: %s.' % self.local_dst_dir)
            if os.path.exists(self.local_dst_dir):
                shutil.rmtree(self.local_dst_dir, onerror=self.sys_opr.error_remove_read_only)
            logger.info('procedure end.')

    def _check_ha_status(self, ssh_client):
        ha_status_cmd = "/opt/dfv/oam/oam-u/ha/ha/module/hacom/tools" \
                        "/ha_client_tool --gethastatus " \
                        "| grep '^ha' | awk '{print $4}'"
        cmd_ret = ssh_client.send_cmd(ha_status_cmd, '#')
        if "Abnormal\n" in cmd_ret:
            logger.error("status abnormal, %s" % ''.join(cmd_ret))
            err_msg = "ha status abnormal"
            raise HCCIException(621003, err_msg)
        return self._get_ha_standby(ssh_client)

    def _get_ha_standby(self, ssh_client):
        ha_info_cmd = "/opt/dfv/oam/oam-u/ha/tools/getHAStatus.sh " \
                      "| grep HA_MODE | awk -F : '{print $2}'|awk '$1=$1'"
        cmd_ret = ssh_client.send_cmd(ha_info_cmd, '#')
        if "single\n" in cmd_ret:
            logger.error("single mode, %s " % ''.join(cmd_ret))
            self.single_mode = True
        else:
            logger.info("double mode, %s " % ''.join(cmd_ret))
            ha_role_cmd = "/opt/dfv/oam/oam-u/ha/tools/getHAStatus.sh" \
                          "| grep LOCAL_ROLE | awk -F : '{print $2}' " \
                          "| awk '$1=$1'"
            cmd_ret = ssh_client.send_cmd(ha_role_cmd, '#')
            if "active\n" in cmd_ret:
                return ErrorInfo.ERROR_IS_MASTER
            if "standby\n" in cmd_ret:
                return ErrorInfo.ERROR_IS_STANDBY
        return ErrorInfo.ERROR_IS_MASTER

    def _try_clouda_self_upgrade(self, node_ip, node_username,
                                 node_password, root_password, nodes_list):
        ssh_client = None
        remote_tmp_pkg_dir = self.remote_pkg_dir_remote
        try:
            ssh_client = StorageSSHClient(node_ip, node_username,
                                          node_password)
            logger.info('Create ssh client for %s success' % node_ip)
            ssh_client.switch_root(root_password)

            logger.info('Change user to root success')

            if ErrorInfo.ERROR_IS_STANDBY == self._check_ha_status(ssh_client):
                return ErrorInfo.ERROR_IS_STANDBY

            deploymanager_pkg_name = SshPublicMethod().get_deploymanager_pkg_name(ssh_client, self.local_pkg_dir)

            local_pkg_path = os.path.join(self.local_pkg_dir,
                                          deploymanager_pkg_name)
            remote_pkg_path = os.path.join(
                remote_tmp_pkg_dir, deploymanager_pkg_name).replace('\\', '/')

            mkdir_cmd = "mkdir -p {pkg}; chmod 777 {pkg}; ls -l /home " \
                        "| grep self_upgrade_tmp" \
                .format(pkg=remote_tmp_pkg_dir)
            cmd_ret = ssh_client.send_cmd(mkdir_cmd, '#')
            cmd_ret = ''.join(cmd_ret)
            if "self_upgrade_tmp" not in cmd_ret:
                err_msg = "make dir failed in node %s" % node_ip
                logger.error("%s, ret: %s" % (err_msg, cmd_ret))
                raise HCCIException(621003, err_msg)

            ssh_client.upload(local_pkg_path.replace('\\', '/'),
                              remote_tmp_pkg_dir.replace('\\', '/'))
            ssh_client = StorageSSHClient(node_ip, node_username,
                                          node_password)
            logger.info('Create ssh client for %s success' % node_ip)
            ssh_client.switch_root(root_password)
            self.sys_opr.un_tar_pkg(ssh_client, remote_pkg_path, self.remote_pkg_dir_remote)

            self._clouda_self_upgrade(ssh_client, deploymanager_pkg_name,
                                      nodes_list)

        except Exception as e:
            logger.error("try self upgrade node:%s failed" % node_ip)
            raise HCCIException(621003, e)
        finally:
            if ssh_client:
                if not ssh_client.is_root:
                    ssh_client.switch_root(root_password)
                clear_pkg_cmd = "rm -rf %s ; " \
                                "echo last_result=$?" % remote_tmp_pkg_dir
                cmd_ret = ssh_client.send_cmd(clear_pkg_cmd, '#')
                cmd_ret = ''.join(cmd_ret)
                if "last_result=0" not in cmd_ret:
                    logger.info("rm tmp dir: %s failed, echo: %s"
                                % (remote_tmp_pkg_dir, str(cmd_ret)))

    def _clouda_self_upgrade(self, ssh_client, deploymanager_pkg_name, nodes_list):
        self_upgrade_action_dir = "{}/{}/action/".format(
            self.remote_pkg_dir_remote,
            os.path.splitext(os.path.splitext(deploymanager_pkg_name)[0])[0]
        )
        change_dir_cmd = "cd {}".format(self_upgrade_action_dir)
        cmd_ret = ssh_client.send_cmd(change_dir_cmd, '#', 10)
        logger.debug("cmd_ret is %s" % cmd_ret)
        SshPublicMethod().check_status_opr(ssh_client)

        self._do_clouda_self_upgrade(ssh_client, nodes_list)

    def _do_clouda_self_upgrade(self, ssh_client, nodes_list):
        """
            cloud agent self-upgrade
        """
        check_clouda_self_upgrade_cmd = \
            "sh ./upgrade.sh upgrade_clouda_available"
        cmd_ret = ssh_client.send_cmd(check_clouda_self_upgrade_cmd, '#')
        cmd_ret = ''.join(cmd_ret)
        if "this version upgrade_clouda_is_available" in cmd_ret:
            self_upgrade_clouda_cmd = "sh ./upgrade.sh clouda"
            echo_str = "please input DeviceManager username"
            logger.info("wait: %s" % echo_str)
            cmd_ret = ssh_client.send_cmd(self_upgrade_clouda_cmd,
                                          echo_str, 60)
            logger.debug("cmd_ret is %s" % cmd_ret)
            echo_str = "please input local {} password".format(
                self.user_name)
            logger.info("wait: %s" % echo_str)
            cmd_ret = ssh_client.send_cmd(self.user_name, echo_str, 60)
            logger.debug("cmd_ret is %s" % cmd_ret)
            echo_str = "clouda upgrade result is"
            timeout = 5 * 60 * (len(nodes_list) / 20 + 1)
            logger.info("wait: %s, wait %s" % (echo_str, timeout))
            cmd_ret = ssh_client.send_cmd(self.password, echo_str, timeout, sensitive=True)
            cmd_ret = ''.join(cmd_ret)
            if "upgrade clouda success!" in cmd_ret:
                logger.info("exec cloud agent self upgrade success")
            elif "No need to upgrade clouda!" in cmd_ret:
                err_msg = "clouda no need to self upgrade"
                logger.info(err_msg)
            else:
                logger.error("clouda self upgrade failed, "
                             "ret: %s" % str(cmd_ret))
                err_msg = "clouda self upgrade failed"
                logger.error(err_msg)
                raise HCCIException(621003, err_msg)
        else:
            logger.info("not support clouda upgrade, %s" % cmd_ret)
