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

import utils.common.log as logger
from utils.common.ssh_util import Ssh
from utils.common.exception import FCDException
from utils.common.fic_base import TestCase
from utils.common.message import Message
from utils.business.param_util import ParamUtil
from utils.business.account_manage_util import AccountType
from utils.business.dmk_util import DmkApi
from utils.business.dmk_util import DMK_ROLE
from utils.business.manageone_util2 import ManageOneUtil2
from utils.business.service_monitor.service_monitor import Host
from utils.business.service_monitor.service_monitor import AuthProvider
from utils.business.service_monitor.service_monitor import deploy_agent
from plugins.DistributedStorage.scripts.utils.common.DeployConstant import DeployConstant
from plugins.DistributedStorage.scripts.logic.VMOperate import VMOperate
from plugins.DistributedStorage.scripts.logic.InstallOperate import InstallOperate
from plugins.ManageOne.scripts.utils.params import Params


class InstallICAgent(TestCase):
    def __init__(self, project_id, pod_id, fs_args):
        super().__init__(project_id, pod_id)
        self.fs_args = fs_args
        self.dmk_opr = DmkApi()
        self.vm_operate = VMOperate(self.project_id, self.pod_id, self.fs_args)
        self.operate = InstallOperate(self.project_id, self.pod_id, fs_args)
        self.dmk_params_dict = self.dmk_opr.get_dmk_info(self.pod_id)
        self.dmk_ip = self.dmk_params_dict.get('dmk_floatIp')
        self.dmk_sys_user = self.dmk_params_dict.get('dmk_ui_username')
        self.dmk_sys_pwd = self.dmk_params_dict.get('dmk_ui_password')
        self.dmk_init_pwd = self.fs_args.get('dmk_init_pwd')
        self.dmk_update_pwd = self.fs_args.get('dmk_pwd')
        self.component_name = self.fs_args.get('component_name')
        self.sub_component_name = ' '.join([self.fs_args.get('az_id'), self.fs_args.get('sub_component_name')])
        self.dmk_creat_user = DeployConstant.CREATE_DMK_USER
        self.dmk_creat_group = DeployConstant.CREATE_DMK_GROUP
        self.fsm_user = DeployConstant.FSM_USER
        self.dmk_role = DMK_ROLE.GROUP_MANAGER
        self.auth_provider = AuthProvider(self.dmk_ip, "8443", self.dmk_creat_user, self.dmk_update_pwd)
        self.param_util = ParamUtil()
        self.mo_util = ManageOneUtil2()
        self.param_dict = Params(self.project_id, self.pod_id).get_params()
        self.vm_ip_list = []
        self.team_id, self.account_id_root, self.account_id_general = '', '', ''

    def procedure(self):
        """
        针对管理融合、业务分离、业务融合，以及扩容场景：注册dmk用户 -> 增加登录account标识 -> 部署ICAgent -> 配置节点域名

        部署工程、扩AZ kvm新建，fs_args['vm_icagent_boolean'] = True
        新增业务存储、扩AZ(kvm/BMS)复用，fs_args['vm_icagent_boolean'] = False
        复制集群：部署工程开启CSDR复制/存储分离部署、扩AZ新建开启CSDR复制/存储分离部署、新增业务存储--扩复制集群、
                安装可选云服务-云服务器容灾CSDR，fs_args['replication_icagent_boolean'] = True
        """
        try:
            # 记录所有节点登录信息node_list
            node_list = list()
            self.dmk_opr.login_dmk(self.dmk_ip, self.dmk_sys_user, self.dmk_sys_pwd)
            dns_ip_list = self.query_dns_ip_info()
            self.create_dmk_user()
            logger.info('Creating a account Identity')
            self.dmk_opr.login_dmk(self.dmk_ip, self.dmk_creat_user, self.dmk_update_pwd)
            deploy_info_list, osd_list, rep_list = list(), self.fs_args.get('osd_list'), self.fs_args.get('vbs_list')
            if self.fs_args.get('osd_icagent_boolean') and osd_list:
                deploy_info_list.extend(osd_list)
            if self.fs_args.get('replication_icagent_boolean') and rep_list:
                deploy_info_list.extend(rep_list)

            if deploy_info_list:
                self.deploy_icagent_for_separate_storage(deploy_info_list, node_list)

            if self.fs_args.get('vm_icagent_boolean'):
                self.deploy_icagent_for_fsm_vm(node_list)

            # 在所有节点配置域名 -> 在fsm虚拟机和业务存储节点配置防火墙规则 -> 修改/etc/group配置文件
            logger.info('Start config dns ip and add port:26401 to iptables')
            for node_info in node_list:
                ssh_client = self.operate.create_ssh_root_client(node_info[0], node_info[1], node_info[2], node_info[3])
                logger.info('Config dns ip on node:{}'.format(node_info[0]))
                for ip in dns_ip_list:
                    self.config_dns_ip(ssh_client, ip)
                logger.info('Config dns successfully')

                logger.info('Start add port:26401 to iptables: {}'.format(node_info[0]))
                self.add_port_to_iptables_for_mo(ssh_client, node_info[0])
                logger.info('Add port successfully')

                logger.info('Modify the configuration file: /etc/group')
                self.mo_verify_pwd_config(ssh_client, node_info[0])
                logger.info('The configuration file is modified successfully')

                Ssh.ssh_close(ssh_client)

            logger.info('ICAgent deployed successfully')
            return Message(200)

        except Exception as e:
            logger.error(traceback.format_exc())
            return Message(500, e)

    def deploy_icagent_for_separate_storage(self, deploy_info_list, node_list):
        """
        业务分离存储节点上部署icagent
        :param deploy_info_list:
        :param node_list:
        :return:
        """
        for osd_info in deploy_info_list:
            account = osd_info.get('user')
            account_ip = osd_info.get('om_ip')
            account_pwd = osd_info.get('passwd')
            account_root_pwd = osd_info.get('root_pwd')
            node_list.append([account_ip, account, account_pwd, account_root_pwd])

            # 增加OSD节点用户标识
            logger.info('Start to create osd node password identity')
            self.add_ssh_account(account, account_pwd, account_root_pwd)
            # osd节点部署ICAgent
            self.deploy_ic_agent([account_ip], account)
            logger.info('The ICAgent is successfully deployed on OSD node: [{}]'.format(account_ip))
            # 删除OSD节点用户标识
            logger.info('Delete dmk account by root id')
            self.dmk_opr.delete_dmk_account(self.account_id_root)
            logger.info('Delete dmk account by general id')
            self.dmk_opr.delete_dmk_account(self.account_id_general)
            logger.info('Delete {} account successfully'.format(account))
        logger.info('Creating a osd nodes account identity successfully')

    def deploy_icagent_for_fsm_vm(self, node_list):
        # 增加fsm用户标识
        float_ip = self.fs_args.get('float_ip')
        fsadmin_pwd = self.fs_args.get('fsadmin_pwd')
        fsm_root_pwd = self.fs_args.get('fsm_root_pwd')
        logger.info('Query vm info')
        master_fsm, standby_fsm = self.vm_operate.get_vm_data(self.pod_id, float_ip)
        logger.info('Query vm info successfully')
        self.vm_ip_list.extend([master_fsm.get('om_ip'), standby_fsm.get('om_ip')])
        vm_info_list = [[vm_ip, self.fsm_user, fsadmin_pwd, fsm_root_pwd] for vm_ip in self.vm_ip_list]
        node_list.extend(vm_info_list)
        logger.info('Start to create VM password identity')
        self.add_ssh_account(self.fsm_user, fsadmin_pwd, fsm_root_pwd)
        logger.info('Creating a vm nodes account identity successfully')

        # FSM虚拟机部署ICAgent
        logger.info('Start to deploy ICAgent on VM: [{}]'.format(self.vm_ip_list))
        self.deploy_ic_agent(self.vm_ip_list, self.fsm_user)
        logger.info('The ICAgent is successfully deployed on VM: [{}]'.format(self.vm_ip_list))

    def query_dns_ip_info(self):
        """
        查询DNS域名服务器IP：dns_ntp_om_ip_01, dns_ntp_om_ip_01
        """
        logger.info('query the DNS IP')
        public_config = self.dmk_opr.get_dmk_public_config()
        config_dict = yaml.safe_load(public_config)
        dns_ip_list = config_dict.get('g_dns').get('ip')
        if not dns_ip_list:
            err_msg = 'Failed to query the DNS IP: dns_ntp_om_ip_01 and dns_ntp_om_ip_01. ' \
                      'result: {}'.format(dns_ip_list)
            logger.error(err_msg)
            raise FCDException(626330, err_msg)
        logger.info('DNS IP: {}'.format(dns_ip_list))
        return dns_ip_list

    def create_dmk_user(self):
        """
        注册DMK账号
        """
        # 创建DMK新的用户
        logger.info('Start to create dmk account')
        logger.info('Register a new DMK account')
        self.team_id, user_id = self.dmk_opr.create_dmk_user(
            self.dmk_creat_user, self.dmk_init_pwd, self.dmk_role, self.dmk_creat_group)
        if not self.team_id or not user_id:
            err_msg = "failed to create installation account"
            logger.error(err_msg)
            raise FCDException(626323)
        logger.info('The new DMK user: [team id:{}, user id:{}] is registered successfully'
                    .format(self.team_id, user_id))
        # 更新用户属组
        logger.info('Update user team')
        res = self.dmk_opr.update_user_to_multi_team(user_id, self.dmk_role, ['OTD', self.dmk_creat_group])
        if not res:
            err_msg = 'failed to update user OTD'
            logger.error(err_msg)
            raise FCDException(626323)

        # 更新账号密码
        logger.info('Update user passwd')
        self.dmk_opr.login_dmk(self.dmk_ip, self.dmk_creat_user, self.dmk_init_pwd)
        res = self.dmk_opr.change_dmk_user_passwd(user_id, self.dmk_init_pwd, self.dmk_update_pwd)
        if not res:
            err_msg = "change dmk user: %s password failed" % user_id
            logger.error(err_msg)
            raise FCDException(626324)
        logger.info("change user %s password success" % user_id)
        logger.info('The DMK account is successfully created')

    def add_ssh_account(self, account, account_pwd, account_sudo_pwd):
        """
        账号增加统一密码标识，格式：region-id,部件名,子部件名,帐户名,帐户类型（数字）
        """
        logger.info('Query region id')
        region_id = self.param_util.get_param_value(self.pod_id, '', '', 'region0_id')
        logger.info('region id:{}'.format(region_id))
        account_identity = '%s,%s,%s,%s,%s' % (region_id, self.component_name,
                                               self.sub_component_name, account, AccountType.MM_OS)
        root_account_identity = '%s,%s,%s,root,%s' % (region_id,
                                                      self.component_name, self.sub_component_name, AccountType.HM_OS)

        logger.info('Add root Identity')
        self.account_id_root = self.dmk_opr.add_account_to_dmk(
            'root', self.team_id, account_sudo_pwd, account_sudo_pwd,
            account_identity=root_account_identity,
            sudo_account_identity=root_account_identity)

        logger.info('Add {} Identity'.format(account))
        self.account_id_general = self.dmk_opr.add_account_to_dmk(
            account, self.team_id, account_pwd, account_sudo_pwd,
            account_identity=account_identity,
            sudo_account_identity=root_account_identity)
        if self.account_id_general and self.account_id_root:
            logger.info(
                "add account {} to dmk success,the account id is : {}".format(account, self.account_id_general))
        else:
            logger.error("add account {} to dmk failed".format(account))
            raise FCDException(626323)

    def deploy_ic_agent(self, ip_list, remote_user):
        """
        调用标准接口部署ICAgent
        """
        logger.info('Deployment ICAgent list: {}'.format(ip_list))
        hosts = [Host(ip, 22, ip, ip) for ip in ip_list]

        return deploy_agent(self.pod_id, self.auth_provider, hosts, remote_user, 'su')

    def deploy_opsagent_by_rest(self):
        """
        登录ManageOne运维节点，创建并执行python脚本，发送post请求触发即刻安装opsAgent
        """
        logger.info('Query moService01Ip')
        mo_service01_ip = self.param_dict.get("moService01Ip")
        if not mo_service01_ip:
            err_msg = 'Failed to query moService01Ip'
            logger.error(err_msg)
            raise Exception(err_msg)
        logger.info('moService01Ip: {}'.format(mo_service01_ip))
        sopuser_pwd = self.mo_util.getSopuserPassWdInfo(self.pod_id)
        root_pwd = self.mo_util.getRootPassWdInfo(self.pod_id)
        client = None
        try:
            logger.info('Connect to the host as the root user: [{}]'.format(mo_service01_ip))
            client = self.operate.create_ssh_root_client(mo_service01_ip, "sopuser", sopuser_pwd, root_pwd)

            cmd_list = ['echo "' + PYTHON_SCRIPTS + '" > /home/ossadm/deploy_ops_agent.py',
                        'chmod 755 /home/ossadm/deploy_ops_agent.py',
                        'chown -h ossadm:ossgroup /home/ossadm/deploy_ops_agent.py',
                        'echo last_result=$?']
            cmd_result = Ssh.ssh_exec_command_return(client, ';'.join(cmd_list))
            cmd_result = str(cmd_result)
            if cmd_result.find('last_result=0') == -1:
                Ssh.ssh_close(client)
                raise FCDException(626329, mo_service01_ip, cmd_result)
            logger.info('Result of creating a Python script:{}'.format(cmd_result))

            cmd = f'su - ossadm -c ". /opt/oss/manager/agent/bin/engr_profile.sh;' \
                  f'python /home/ossadm/deploy_ops_agent.py {mo_service01_ip};echo $?"'
            cmd_result = Ssh.ssh_exec_command_return(client, cmd)
            cmd_result = str(cmd_result)
            if cmd_result.find('0') == -1:
                Ssh.ssh_close(client)
                raise FCDException(626329, mo_service01_ip, cmd_result)
            logger.info('Result of executing the Python script:{}'.format(cmd_result))

            cmd = ";".join(['rm -rf /home/ossadm/deploy_ops_agent.py', 'echo last_result=$?'])
            cmd_result = Ssh.ssh_exec_command_return(client, cmd)
            cmd_result = str(cmd_result)
            if cmd_result.find('last_result=0') == -1:
                Ssh.ssh_close(client)
                raise FCDException(626329, mo_service01_ip, cmd_result)

            Ssh.ssh_close(client)
        except Exception as e:
            logger.error(traceback.format_exc())
            raise FCDException(626329, mo_service01_ip, e)
        finally:
            if client:
                Ssh.ssh_close(client)

    @staticmethod
    def config_dns_ip(ssh_client, ip):
        cmd_list = [f'echo nameserver {ip} >> /etc/resolv.conf', 'echo last_result=$?']
        cmd = ';'.join(cmd_list)
        cmd_result = Ssh.ssh_exec_command_return(ssh_client, cmd)
        cmd_result = str(cmd_result)
        if cmd_result.find('last_result=0') == -1:
            Ssh.ssh_close(ssh_client)
            err_msg = "Config dns ip failed: [cmd:{}, result:{}".format(cmd, cmd_result)
            logger.error(err_msg)
            raise Exception(err_msg)

    @staticmethod
    def add_port_to_iptables_for_mo(ssh_client, ip_address):
        logger.info('Starting to add port:26401 to iptables')
        cmd_echo = "echo '"
        cmd_python_file = "' > /home/storage_iptables_tmp.sh"
        cmd_res = 'echo last_result=$?'
        cmd = ";".join([cmd_echo + SHELL_EXPRESSION + cmd_python_file, cmd_res])
        cmd_result = Ssh.ssh_exec_command_return(ssh_client, cmd)
        cmd_result = str(cmd_result)
        if cmd_result.find('last_result=0') == -1:
            Ssh.ssh_close(ssh_client)
            raise FCDException(626329, ip_address, cmd_result)
        cmd = ";".join(['bash /home/storage_iptables_tmp.sh', 'echo last_result=$?'])
        cmd_result = Ssh.ssh_exec_command_return(ssh_client, cmd)
        cmd_result = str(cmd_result)
        if cmd_result.find('last_result=0') == -1:
            logger.error('Config iptables failed')
            Ssh.ssh_close(ssh_client)
            raise FCDException(626329, ip_address, cmd_result)

        cmd = ";".join(['rm -rf /home/storage_iptables_tmp.sh', 'echo last_result=$?'])
        cmd_result = Ssh.ssh_exec_command_return(ssh_client, cmd)
        cmd_result = str(cmd_result)
        if cmd_result.find('last_result=0') == -1:
            Ssh.ssh_close(ssh_client)
            raise FCDException(626329, ip_address, cmd_result)

    @staticmethod
    def mo_verify_pwd_config(ssh_client, ip_address):
        """
        修改/etc/group配置文件，目的：保证操作  ManageOne运维面 -> 密码管理 -> 校验  能够成功。
        """
        cmd = "usermod -G wheel nobody;echo cmd_result=$?"
        logger.info('cmd is: {}'.format(cmd))
        cmd_result = Ssh.ssh_exec_command_return(ssh_client, cmd)
        cmd_result = str(cmd_result)
        if cmd_result.find('cmd_result=0') == -1:
            Ssh.ssh_close(ssh_client)
            raise FCDException(626329, ip_address, cmd_result)
        logger.info('cmd result: {}'.format(cmd_result))


SHELL_EXPRESSION = """#!/usr/bin/bash
if [ -z "$(cat /etc/sysconfig/iptables | grep "\-A INPUT \-p tcp \-m tcp \-\-dport 26401 \-j ACCEPT")" ];then
    iptables -I INPUT -p tcp --dport 26401 -j ACCEPT >/dev/null 2>&1
fi
"""

PYTHON_SCRIPTS = """# -*- coding: utf-8 -*-
import sys
from util.httpclient import IRHttpClient
from util.httpclient import CommonHttpClient

def deploy_opsagent(ip_address):
    client = CommonHttpClient(ip_address, 32018, True, False)
    status, rsp = client.post('/rest/moautoops/v1/cron/syn-devices',)
    if status != 200:
        return 'failed'
    return 'success'


if __name__ == '__main__':
    ip_addr = sys.argv[1]

    res = deploy_opsagent(ip_addr)
    print(res)
"""
