# -*- coding: utf-8 -*-
# Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved.
from utils.common.fic_base import TestCase
import utils.common.log as logger
from utils.common.exception import FCDException
from platforms.project.ProjectUtils import get_project_condition_boolean
from plugins.DistributedStorage.scripts.logic.DeployOperate import DeployOperate
from plugins.DistributedStorage.scripts.utils.common.DeployConstant import DeployConstant
from plugins.DistributedStorage.scripts.logic.vm_operate import VMOperate


FSM_CONDITION = '(ManageStorFB80|(ManageStorFB80&RegionConHA))|' \
                '(ManageStorFB80&ProjectModifactionRegionConHA&RegionConHA)|' \
                'TenantStorFBHCI80|TenantStorFB80|' \
                'TenantStorFB80&(ExpansionAZ_KVM|ExpansionServiceStorage)|TenantStorFB80&(ExpansionAZ_BMS)'
EXPAND_NODE_OR_POOL_CONDITION = '(TenantStorFBReuse80)&(ExpansionAZ_KVM|ExpansionAZ_BMS)|' \
                                'ExpansionServiceStorage&(TenantStorNewPool|TenantStorNewNode)|' \
                                '(ExpansionAdCloudService|ExpansionServiceStorage)&(CSHAStorage_TFB|CSDRStorage_TFB)'


class EnableOSSandbox(TestCase):
    def __init__(self, project_id, pod_id, fs_args_list):
        super(EnableOSSandbox, self).__init__(project_id, pod_id)
        self.fs_args_list = fs_args_list

    def procedure(self):
        logger.info('Start to configure OS sandbox.')
        for fs_args in self.fs_args_list:
            float_ip = fs_args.get('float_ip')
            if not float_ip:
                continue
            update_pwd = fs_args.get('dm_update_pwd')
            opr = DeployOperate(fs_args)
            opr.login(DeployConstant.DM_LOGIN_USER, update_pwd)
            # 判断是否开启节点沙箱，新建场景开启节点沙箱，扩节点/池由原存储FSM节点沙箱状态决定
            if not self.need_enable_node_sandbox(opr):
                logger.info("Current situation don't neet to enable node sandbox")
                continue
            node_ips = self.get_nodes_info(fs_args, mode='enable')
            self.enable_sandbox(opr, node_ips)
            self.check_node_sandbox_status(opr, node_ips, mode='enable')
        logger.info('Configure OS sandbox successfully.')

    def cleanup(self):
        logger.info('Start to rollback enabled OS sandbox')
        for fs_args in self.fs_args_list:
            float_ip = fs_args.get('float_ip')
            if not float_ip:
                continue
            update_pwd = fs_args.get('dm_update_pwd')
            opr = DeployOperate(fs_args)
            opr.login(DeployConstant.DM_LOGIN_USER, update_pwd)
            if not self.need_enable_node_sandbox(opr):
                logger.info("Current situation don't neet to disable node sandbox")
                continue
            self.query_sandbox_configuration_info(opr)
            node_infos = self.get_nodes_info(fs_args, mode='disable')
            self.disable_sandbox(opr, node_infos)
            self.check_node_sandbox_status(opr, node_infos, mode='disable')
        logger.info('Rollback enabled OS sandbox successfully.')

    def need_enable_node_sandbox(self, opr):
        # 新建场景开启节点沙箱
        enable_node_sandbox = True
        # 扩节点/池由原存储FSM节点沙箱状态决定, 若存在FSM节点开沙箱则新扩容节点开启沙箱，否则不开
        if get_project_condition_boolean(self.project_id, EXPAND_NODE_OR_POOL_CONDITION):
            enable_node_sandbox = False
            rsp_data = self.query_cluster_servers_info(opr)
            for server in rsp_data:
                node_role = server.get('role')
                if 'management' not in node_role:
                    continue
                sandbox_status = server.get('sandbox_status')
                node_ip = server.get('management_ip')
                if sandbox_status == 0:
                    enable_node_sandbox = True
                    logger.info('management node [%s] sandbox is enable.' % node_ip)
            if not enable_node_sandbox:
                logger.info("FSM node sandbox status is disable, "
                            "in expansion condition don't need to enable new node sandbox")
        return enable_node_sandbox

    def get_nodes_info(self, fs_args, mode):
        logger.info('Get nodes information for sandbox operation.')
        enable_node_list = []
        disable_node_list = []
        admin_pwd = fs_args.get('dm_update_pwd')
        # 新建虚拟机场景获取主备fsm ip
        if get_project_condition_boolean(self.project_id, FSM_CONDITION):
            vm_operate = VMOperate(self.project_id, self.pod_id, fs_args)
            master_fsm, standby_fsm = vm_operate.get_vm_data(self.pod_id, fs_args.get('float_ip'))
            master_fsm_ip = master_fsm.get('om_ip')
            standby_fsm_ip = standby_fsm.get('om_ip')
            fsm_ip = [master_fsm_ip, standby_fsm_ip]
            fsm_root_pwd = master_fsm.get('root_pwd')
            disable_nodes = {'node_ips': fsm_ip,
                             'root_password': fsm_root_pwd,
                             'admin_password': admin_pwd}
            enable_node_list.append(master_fsm_ip)
            enable_node_list.append(standby_fsm_ip)
            disable_node_list.append(disable_nodes)

        # 管理融合部署只开启FSM节点沙箱
        if fs_args.get('create_vm_service_name') == "DistributedStorageManage":
            if mode == 'enable':
                return enable_node_list
            else:
                return disable_node_list

        osd_list = fs_args.get('osd_list')
        if osd_list:
            for osd_node in osd_list:
                self._get_disable_storage_node_info(admin_pwd, disable_node_list, osd_node)
                enable_node_list.append(osd_node.get('om_ip'))
        if mode == 'enable':
            return enable_node_list
        else:
            return disable_node_list

    def enable_sandbox(self, opr, node_ips):
        logger.info('Start to enable OS sandbox for nodes.')
        data = opr.enable_os_sandbox(node_ips)
        failed_nodes_list = []
        for node in data:
            if node.get('code') != 0:
                failed_nodes_list.append(node)
        if failed_nodes_list:
            err_msg = 'Failed enable sandbox nodes list: %s' % failed_nodes_list
            logger.error(err_msg)
            raise FCDException(626389, failed_nodes_list)

    def check_node_sandbox_status(self, opr, node_infos, mode):
        logger.info('Check node sandbox status.')
        rsp_data = self.query_cluster_servers_info(opr)
        if mode == 'enable':
            self.check_enable_sandbox_status(node_infos, rsp_data)
        else:
            self.check_disable_sandbox_status(node_infos, rsp_data)

    def query_cluster_servers_info(self, opr):
        rsp_obj = opr.query_cluster_servers()
        rsp_code, rsp_result, rsp_data = rsp_obj.get_rsp_data()
        err_code = rsp_result.get('code')
        if rsp_code != 0 or err_code != 0:
            error_des = rsp_result.get('description')
            error_sgt = rsp_result.get('suggestion')
            err_msg = "Failed to query cluster nodes info, Detail:[%s]%s.Suggestion:%s" \
                      % (err_code, error_des, error_sgt)
            logger.error(err_msg)
            raise Exception(err_msg)
        return rsp_data

    def check_disable_sandbox_status(self, node_infos, rsp_data):
        node_list = []
        disable_failed_nodes = []
        for node_set in node_infos:
            node_list += node_set.get('node_ips')
        for server in rsp_data:
            node_ip = server.get('management_ip')
            if node_ip not in node_list:
                continue
            if server.get('sandbox_status') != 1:
                disable_failed_nodes.append(node_ip)
        if disable_failed_nodes:
            err_msg = 'The follow nodes [%s] OS sandbox status is not disabled.' % disable_failed_nodes
            logger.error(err_msg)
            raise FCDException(626385, disable_failed_nodes)
        logger.info("Nodes [%s] sandbox status is disable" % node_list)

    def check_enable_sandbox_status(self, node_infos, rsp_data):
        enable_failed_nodes = []
        for server in rsp_data:
            node_ip = server.get('management_ip')
            if node_ip not in node_infos:
                continue
            if server.get('sandbox_status') != 0:
                enable_failed_nodes.append(node_ip)
        if enable_failed_nodes:
            err_msg = 'The follow nodes [%s] OS sandbox status is not enabled.' % enable_failed_nodes
            logger.error(err_msg)
            raise FCDException(626385, enable_failed_nodes)
        logger.info("Nodes [%s] sandbox status is enable" % node_infos)

    def query_sandbox_configuration_info(self, opr):
        logger.info('Query the Security Sandbox Configuration Information of the Cluster OS')
        data = opr.query_os_sandbox()
        if data.get('support_disable_sandbox') != 0:
            err_msg = 'The cluster OS security sandbox is not supported to be disabled.'
            logger.error(err_msg)
            raise Exception(err_msg)
        logger.info('The cluster OS security sandbox is supported to be disabled.')

    def disable_sandbox(self, opr, node_infos):
        logger.info('Start to disable OS sandbox for nods.')
        failed_nodes_list = []
        for node_info in node_infos:
            data = opr.disable_os_sandbox(node_info)
            for node in data:
                if node.get('code') != 0:
                    failed_nodes_list.append(node)
        if failed_nodes_list:
            err_msg = 'Failed disable sandbox nodes list: %s' % failed_nodes_list
            logger.error(err_msg)
            raise FCDException(626386, failed_nodes_list)

    def _get_disable_storage_node_info(self, admin_pwd, disable_node_list, node):
        om_ip = [node.get('om_ip')]
        root_pwd = node.get('root_pwd')
        disable_nodes = {'node_ips': om_ip,
                         'root_password': root_pwd,
                         'admin_password': admin_pwd}
        disable_node_list.append(disable_nodes)


