# -*- coding:utf-8 -*-
# Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved.
import pathlib
import re
import traceback

from utils.common.fic_base import TestCase
import utils.common.log as logger
from utils.common.exception import FCDException
from utils.business.storage import jbod_libs
from utils.common.param_check import ping
from utils.common.ssh_util import Ssh
from plugins.DistributedStorage.scripts.logic.InstallOperate import InstallOperate
from plugins.DistributedStorage.scripts.utils.common.DeployConstant import DeployConstant


class ConfigureDiskJBODMode(TestCase):
    def __init__(self, project_id, pod_id, fs_args):
        super(ConfigureDiskJBODMode, self).__init__(project_id, pod_id)
        self.project_id = project_id
        self.pod_id = pod_id
        self.error = list()
        self.bmc_info_list = fs_args.get("bmc_info_list")

    def procedure(self):
        try:
            self.main()
        except FCDException as e1:
            logger.error(traceback.format_exc())
            raise e1
        except Exception as e2:
            logger.error(traceback.format_exc())
            raise FCDException('626038', str(e2)) from e2

    def main(self):
        ip_list = self._get_ip()
        self._check_ip(ip_list)
        for bmc_ip_info in self.bmc_info_list:
            om_ip = bmc_ip_info.get("manageIp")
            account_info = bmc_ip_info["creuser"].split(',')
            user = account_info[2]
            passwd = account_info[3]
            root_pwd = account_info[1]
            jbod_obj = DistributedStorageConfigJBOD(*[om_ip, user, passwd, root_pwd])
            if not jbod_obj.run():
                self.error.append(om_ip)
        if self.error:
            err_msg = 'Failed to configure jbod, hosts:%s' % self.error
            raise FCDException(626040, err_msg)

    def _get_ip(self):
        return [bmc_info['bmc_ip'] for bmc_info in self.bmc_info_list]

    def _check_ip(self, ip_list):
        for ip in ip_list:
            logger.info('testing network connectivity with %s' % ip)
            if not ping(ip):
                self.error.append(ip)
                logger.info('failed to test network connectivity with %s' % ip)
        if self.error:
            raise FCDException(626039, ','.join(self.error))


class DistributedStorageConfigJBOD(jbod_libs.ConfigureJBOD):
    """分布式存储配置JBOD"""

    # 自定义配置RAID卡JBOD的方法名与对应查询RAID卡的命令和回显判断匹配规则映射
    TYPE_CHECK_MAP = {
        "config_1880_jbod_handle": (DeployConstant.DRIVER_TYPE_CONDITION.get("1880raid").get("cmd"),
                                    DeployConstant.DRIVER_TYPE_CONDITION.get("1880raid").get("pattern")),
        "config_3152_jbod_handle": (DeployConstant.DRIVER_TYPE_CONDITION.get("bp3152").get("cmd"),
                                    DeployConstant.DRIVER_TYPE_CONDITION.get("bp3152").get("pattern"))
    }

    def __init__(self, *args, **kwargs):
        super(DistributedStorageConfigJBOD, self).__init__(*args, **kwargs)
        self.ssh_client = InstallOperate.create_ssh_root_client(*args)

    def run(self):
        try:
            ret = getattr(self, self.get_config_jbod_handle(), self.enable_jbod)()
        except Exception as e:
            logger.error("Error:{}".format(e))
            raise e
        finally:
            Ssh.ssh_close(self.ssh_client)
        return ret

    def get_config_jbod_handle(self):
        """校验是否由插件配置JBOD"""
        handle = ""
        for _handle, (check_cmd, check_pattern) in self.TYPE_CHECK_MAP.items():
            ret = Ssh.ssh_exec_command_return(self.ssh_client, check_cmd)
            logger.info("Node:{}, config raid handle:{}, cmd result:{}".format(self.os_ip, _handle, ret))
            if re.search(check_pattern, str(ret)):
                handle = _handle
                break
        return handle

    def config_3152_jbod_handle(self):
        """bp3152RAID卡无JBOD，跳过"""
        logger.info("[{}]This node is a 3152 RAID card. Skip".format(self.os_ip))
        return True

    def config_1880_jbod_handle(self, enable=True):
        tool_name = "tools.tar.gz"
        self.upload_tool(src=str(DeployConstant.TOOL_PATH).format(tool_name))
        cmd = "mkdir -p /opt/MegaRAID/storcli/ && " \
              "tar -zxf /tmp/{} -C /opt/MegaRAID/storcli/ && " \
              "chmod +x /opt/MegaRAID/storcli/hiraidadm && " \
              "whoami".format(tool_name)
        try:
            self.install_tool(tool_name, cmd, expect="root")
            self.install_1880_storcli64()
            cmd = "ctrlcount=$(/opt/MegaRAID/storcli/hiraidadm show ctrlcount | grep 'ctrlcount' | " \
                  "awk -F : '{print $2}' | sed 's/ //g');" \
                  "for((controller=0;controller<$ctrlcount;controller++));" \
                  "do /opt/MegaRAID/storcli/hiraidadm c$controller set jbod=%s; done"
            if enable:
                ret = self.config_jbod(cmd=cmd % "rawdrive", another_except="the feature has been enabled")
            else:
                ret = self.config_jbod(cmd=cmd % "off", another_except="the feature has been disabled")
        finally:
            self.clear_tool(tool_name)
        return ret

    def install_1880_storcli64(self):
        cmd = "rpm -Uvh /opt/MegaRAID/storcli/hiraidadm*aarch64.rpm"
        ret = Ssh.ssh_exec_command_return(self.ssh_client, cmd, timeout=20)
        if str(ret).__contains__("The installation has been completed") \
                or str(ret).__contains__("is already installed"):
            logger.info(ret)
            return
        logger.error("install storcli failed, details:{}".format(ret))
        raise Exception(ret)

    def upload_tool(self, src: str, dst: str = "/tmp"):
        """上传JBOD配置工具到节点"""
        cmd = "[ -e {0} ] && rm -f {0} && whoami".format(pathlib.Path(dst, pathlib.Path(src).name))
        Ssh.ssh_send_command(self.ssh_client, cmd, expect="root", timeout=10)
        Ssh.put_file(self.os_ip, self.username, self.password, src, dst)
        logger.info('copy {} to node[{}] success!'.format(src, self.os_ip))

    def install_tool(self, tool_name, cmd, expect="root", timeout=20):
        """安装JBOD配置工具"""
        Ssh.ssh_send_command(self.ssh_client, cmd, expect=expect, timeout=timeout)
        logger.info("The JBOD tool[{}] is successfully installed on the node[{}].".format(tool_name, self.os_ip))

    def clear_tool(self, tool_name, dst: str = "/tmp"):
        """清理节点上的工具包"""
        cmd = "[ -e {0} ] && rm -f {0} && whoami".format(pathlib.Path(dst, tool_name))
        Ssh.ssh_send_command(self.ssh_client, cmd, expect="root", timeout=10)
        logger.info("Tool package {} deleted successfully".format(tool_name))

    def config_jbod(self, cmd, expect="Success", another_except=None, timeout=20):
        """配置JBOD"""
        res = True
        ret = Ssh.ssh_exec_command_return(self.ssh_client, cmd, timeout=timeout)
        if str(ret).__contains__(expect) or str(ret).__contains__(another_except):
            logger.info("The JBOD is successfully configured on the node[{}]".format(self.os_ip))
        else:
            res = False
            msg = 'Failed to configure the JBOD, node:{}, details:{}'.format(self.os_ip, ret)
            logger.error(msg)
        return res
