# -*- coding: utf-8 -*-
# Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved.
import utils.common.log as logger
from utils.common.ssh_util import Ssh
from utils.client.FSPAuthClient import FSPAuthClient
from utils.common.exception import HCCIException
from utils.common.OpenStackNodeManager import OpenStackNodeManager
from utils.PasswordManager.PasswordManager import FSPasswordManager
from utils.Driver.CloudDC.OpenStack.get_host_info import GetHostInfo
from utils.Driver.CloudDC.OpenStack.config_cascading_kvm import ConfinCascadingKvm

from utils.business.project_condition_utils import get_project_conditions
from utils.business.project_condition_utils import get_project_condition_boolean

from plugins.DistributedStorage.logic.deploy_operate import DeployOperate
from plugins.DistributedStorage.logic.install_operate import InstallOperate
from plugins.DistributedStorage.utils.common.deploy_constant import DeployConstant
from plugins.DistributedStorage.implement.tc_config_kvm_resource_pool import ConfigKVMResourcePoolFather


class ConfigResourcePool(ConfigKVMResourcePoolFather):
    def __init__(self, project_id, pod_id, fs_args, **kwargs):
        super(ConfigResourcePool, self).__init__(project_id, pod_id)
        self.float_ip = fs_args.get('float_ip')
        self.vbs_list = fs_args.get('vbs_list')
        self.update_pwd = fs_args.get('dm_update_pwd')
        self.az_id = fs_args.get('az_id')
        self.opr = DeployOperate(fs_args)
        self.more_args = kwargs
        self.bms_condition = get_project_condition_boolean(self.project_id, 'TenantStorFB80&BMS')
        self.install_opr = InstallOperate(self.project_id, self.pod_id, fs_args)
        self.new_pool = get_project_condition_boolean(self.project_id, 'TenantStorNewPool')
        self.is_exp_reuse = get_project_condition_boolean(
            self.project_id, "(TenantStorFBReuse80|TenantStorFBPoolReuse80)&ExpansionAZ_KVM|TenantStorNewPool")

    @classmethod
    def query_cinder_kvm_by_backend_name(cls, cluster_data, enabled_backend):
        cinder_kvm_name = ""
        cluster_list = cluster_data.get('cluster_list')
        if not cluster_list:
            logger.info('The cinder kvm service does not exist')
            return cinder_kvm_name
        for cluster in cluster_list:
            cinder_drivers = cluster["params"]["cinder_drivers"]
            if not cinder_drivers:
                continue
            backend_store = cinder_drivers[0]["backend_store"]
            if backend_store != 'fusionstorage':
                continue
            has_found = False
            section_list = cinder_drivers[0]["cfg"]['section_list']
            for section in section_list:
                if section['volume_backend_name'] == enabled_backend:
                    cinder_kvm_name = cluster["params"]["host"]
                    logger.info('backend name:{}, exist cinder-kvm:{}'.format(enabled_backend, cinder_kvm_name))
                    has_found = True
                    break
            if has_found:
                break
        return cinder_kvm_name

    @staticmethod
    def get_fsp_ssh_client(pod_id, ip):
        """ Get FusionSphere Openstack ssh client

        steps of get fusionSphere openstack ssh client:
            1. logining with fsp.
            2. switching to root
            3. importing openstack environment

        :param pod_id: openstack pod id
        :param ip:
        :return: ssh_client
        """
        logger.info("Get host's(%s) ssh logined client" % ip)
        fsp_pass_manager = FSPasswordManager(pod_id)
        fsp_password = fsp_pass_manager.get_fsp_password()
        fsp_ssh_client = Ssh.ssh_create_client(ip, "fsp", fsp_password)

        root_password = fsp_pass_manager.get_root_password()
        Ssh.ssh_send_command(fsp_ssh_client, "su", 'Password:', 300)
        Ssh.ssh_send_command(fsp_ssh_client, root_password, '#', 300)

        env_os_password = fsp_pass_manager.get_env_os_password()
        Ssh.ssh_send_command(fsp_ssh_client, "source set_env", '1|2', 300)
        Ssh.ssh_send_command(fsp_ssh_client, "1", 'OS_USERNAME', 300)
        Ssh.ssh_send_command(fsp_ssh_client, env_os_password, '#', 300)
        logger.info('Get host(%s) logined client success' % ip)
        return fsp_ssh_client

    @staticmethod
    def rollback_get_section_list_while_new_pool(exist_section_list, section_list):
        """
        LLD表后端名存在，且pool_id存在：若对接的pool_id，都是LLD表存储池对应的pool_id，删后端；否则删除pool_id，不删后端
        """
        section_dict = dict((section['volume_backend_name'], section['pool_id_list']) for section in section_list)
        update_section_list = list()
        for exist_section in exist_section_list:
            if exist_section['volume_backend_name'] not in section_dict.keys():
                update_section_list.append(exist_section)
            else:
                exist_pool_id = set(exist_section['pool_id_list'].split(','))
                lld_pool_id = set(section_dict[exist_section['volume_backend_name']].split(','))
                pub_id = exist_pool_id.intersection(lld_pool_id)
                if not pub_id:
                    continue
                if len(pub_id) == len(exist_pool_id):
                    logger.info('Delete {}'.format(exist_section['volume_backend_name']))
                else:
                    update_pool_id = ','.join(exist_pool_id.difference(pub_id))
                    exist_section['pool_id_list'] = update_pool_id
                    update_section_list.append(exist_section)
        logger.info('update section list:{}'.format(update_section_list))
        return update_section_list

    @staticmethod
    def _param_suffix(parameter, suffix):
        if suffix == 1:
            return parameter
        else:
            return '{}_{}'.format(parameter, suffix)

    @staticmethod
    def _merging_backend(old_section_list, section_list):
        backend_list = [section.get('volume_backend_name') for section in section_list]
        logger.info("old section list: %s" % old_section_list)
        logger.info("section list: %s" % section_list)
        logger.info("backend list: %s" % backend_list)
        reserved_backend = list()
        for old_section in old_section_list:
            old_backend = old_section.get('volume_backend_name')
            if old_backend not in backend_list:
                reserved_backend.append(old_section)
                continue
            for section in section_list:
                backend = section.get('volume_backend_name')
                if old_backend != backend:
                    continue
                logger.info("meraging old backend: %s, backend: %s" % (old_backend, backend))
                pool_ids = section.get('pool_id_list')
                pool_id_list = pool_ids.split(',')
                old_pool_ids = old_section.get('pool_id_list')
                old_pool_id_list = old_pool_ids.split(',')
                pool_id_list = list(set(pool_id_list).union(set(old_pool_id_list)))
                section['pool_id_list'] = ','.join(pool_id_list)
        section_list.extend(reserved_backend)
        logger.info("merged backend list: %s" % section_list)

    @staticmethod
    def _decrypt_obs(ssh_client, s3_store_access_key_for_cinder, s3_store_secret_key_for_cinder):
        cmd_set = "rm /home/fsp/get_key_for_cinder.py"
        Ssh.ssh_send_command(ssh_client, cmd_set, '#', 300)
        cmd_set0 = "echo '"
        cmd_set1 = "' >> /home/fsp/get_key_for_cinder.py"
        cmd_set = "# -*- coding: utf-8 -*-"
        Ssh.ssh_send_command(ssh_client, cmd_set0 + cmd_set + cmd_set1, '#', 300)
        cmd_set = "from FSSecurity import crypt"
        Ssh.ssh_send_command(ssh_client, cmd_set0 + cmd_set + cmd_set1, '#', 300)
        cmd_set = 'access_key = "%s"' % s3_store_access_key_for_cinder
        Ssh.ssh_send_command(ssh_client, cmd_set0 + cmd_set + cmd_set1, '#', 300)
        cmd_set = 'secret_key = "%s"' % s3_store_secret_key_for_cinder
        Ssh.ssh_send_command(ssh_client, cmd_set0 + cmd_set + cmd_set1, '#', 300)
        cmd_set = 'print(access_key + "||" + crypt.decrypt(secret_key))'
        Ssh.ssh_send_command(ssh_client, cmd_set0 + cmd_set + cmd_set1, '#', 300)
        cmd_set = "python /home/fsp/get_key_for_cinder.py"
        listout = Ssh.ssh_send_command(ssh_client, cmd_set, '#', 300)
        cmd_set = "rm /home/fsp/get_key_for_cinder.py"
        Ssh.ssh_send_command(ssh_client, cmd_set, '#', 300)
        if listout[1]:
            out = listout[1].strip().split("||")
            if len(out) >= 2:
                logger.info("Decrypt obs-info success.")
                return out[0], out[1]
            else:
                logger.info("Decrypt obs-info failed, %s" % listout)
                raise Exception("Decrypt obs-info failed.")
        else:
            logger.error("Decrypt obs-info failed.")
            raise Exception("Decrypt obs-info failed.")

    def procedure(self):
        """
        对接原则：
        1. 部署工程、扩AZ新建存储集群、扩AZ复用、扩计算AZ复用已有存储场景，都会新增一个cinder-kvm00X服务,直接对接。通过LLD表填的az_id和
           enabled_backend查到已存在cinder-kvm00X，说明LLD表填写错误或有历史残留，工步抛错：
              （1） 一个后端内的多个存储池，存储池id通过逗号隔开，对接到一个 后端存储配置名称 内
              （2） 多个后端，cps---配置---资源池管理---配置存储集群---后端存储配置 对应多个配置栏
        2. 新增业务存储--新增存储池场景，往已有AZ内扩存储池，不会新增cinder-kvm00X。通过LLD表填的az_id和enabled_backend应该查到已有的
           cinder-kvm00X，如果未查到，说明LLD表填写错误，工步抛错。对接通过patch方法更新：
             （1） 如果cinder-kvm00X内存在LLD表填写的业务存储后端存储名，则将已有的存储池id和新扩的存储id通过逗号连接，update到cps已有
                  的后端存储配置名称
             （2） 如果cinder-kvm00X内未查到LLD表填写的业务存储后端存储名，则cps---配置---资源池管理---配置存储集群---后端存储配置 新
                  增一栏，对接当前待对接的后端存储
        """
        logger.info('Start to query section list and enabled_backend name')
        pool_name_id_dict = self.get_storage_pool_name_id_map()
        section_list, multi_backend = self.get_multiple_backend_section(pool_name_id_dict)
        enabled_backend = multi_backend[0]

        logger.info('Start to upload certificates and get private key')
        webui_client = FSPAuthClient.get_cps_web_client(self.db, self.project_id, self.pod_id)
        obj = ConfinCascadingKvm(webui_client)
        resource_pool_data = obj.get_kvm_resource_pool()

        old_fscli_cfg = dict()
        if self.is_exp_reuse:
            old_fscli_cfg = self.get_old_fscli_cfg(self.float_ip, resource_pool_data)

        private_key_psw = self.install_opr.upload_cert_and_get_private_key(webui_client)

        logger.info("Start to check multiple enabled backend")
        cinder_driver_info = self.multi_backend_name_config_check(multi_backend, resource_pool_data)

        logger.info("Start to get the cluster name, id and ip of compute nodes or control nodes")
        cluster_name = ''
        new_pool_fs_agent = ''
        if self.new_pool:
            logger.info('This is the increase storage pool scenario')
            cinder_driver_cfg, cluster_name = cinder_driver_info
            logger.info('cluster name:{}'.format(cluster_name))
            new_pool_section_list = cinder_driver_cfg.get('section_list')
            new_pool_fs_agent = cinder_driver_cfg.get('fusionstorageagent')
            enabled_backend = cinder_driver_cfg.get('enabled_backend')
            self._merging_backend(new_pool_section_list, section_list)
        compute_id_list, fs_agent = self.get_fs_agent_id_and_ip_info(obj, webui_client, new_pool_fs_agent)

        logger.info('Start to get last uds image data')
        last_uds_data = obj.get_last_uds_image(resource_pool_data)
        config_cinder_args = [last_uds_data, obj, enabled_backend,
                              fs_agent, section_list, compute_id_list,
                              private_key_psw, cluster_name]
        self._config_cinder_kvm(*config_cinder_args)

        logger.info("Start to check the interconnection result")
        cinder_kvm_name = obj.get_cinder_kvm_name_fusionstorage(self.az_id, enabled_backend)
        if not cinder_kvm_name:
            err_msg = "Failed to interconnect with cinder-kvm00x."
            logger.error(err_msg)
            raise HCCIException(626006, err_msg)

        if self.is_exp_reuse:
            self.update_fscli_cfg(self.float_ip, cinder_kvm_name, old_fscli_cfg)

        logger.info("Config Cinder connect with DistributedStorage success.")

    def get_fs_agent_id_and_ip_info(self, obj, webui_client, new_pool_fs_agent: str):
        if self.bms_condition:
            # 裸金属场景(BMS)：选择三控制节点部署角色(control_id_list);
            # fs_agent与部署角色的三控制节点无对应关系，默认选择2个节点，如果有控制节点，再选择1个控制节点
            host_num = 3
            bms_fs_agent_num = 2
            control_ip_list, control_id_list, _, _ = obj.get_hosts_info_u()
            bms_info = OpenStackNodeManager.get_bms_info(self.db, self.pod_id)
            bms_compute_ip_list = [unit["bms_external_om_ip"] for unit in bms_info][:bms_fs_agent_num]
            if len(control_ip_list) > 0:
                bms_compute_ip_list.append(control_ip_list[0])
            fs_agent = ",".join(bms_compute_ip_list)
            control_id_list = control_id_list[:host_num]
            logger.info('Control nodes id: {}, compute nodes ip: {}'.format(control_id_list, fs_agent))
            return control_id_list, fs_agent
        else:
            selected_compute_nodes = self.select_kvm_compute_node(webui_client, new_pool_fs_agent)
            return list(selected_compute_nodes.values()), ",".join(list(selected_compute_nodes.keys()))

    def select_kvm_compute_node(self, webui_client, new_pool_fs_agent: str):
        """KVM场景：选择至多三个计算节点部署blockstorage-driver-kvm角色

        部署角色的主机ID(传参：compute_id_list)必须与块客户端管理IP(传参：fs_agent)对应；
        单个计算节点最多对接两个cinder-kvm；新增存储池直接使用原cinder-kvmXXX中的计算节点，不存在最多对接两个cinder-kvm问题。
        """
        selected_compute_nodes = {}
        cps_hosts = GetHostInfo(webui_client).get_hosts_info()
        all_host = {host.get("omip"): [host.get("id"), host.get("roles", [])] for host in cps_hosts}
        if self.new_pool:
            for om_ip in new_pool_fs_agent.split(","):
                selected_compute_nodes[om_ip] = all_host[om_ip][0]
        else:
            max_vbs_num = 3
            compute_node_roles = dict()
            for node_info in self.vbs_list:
                if max_vbs_num == 0:
                    break
                om_ip = node_info.get("om_ip")
                host_id, role_list = all_host.get(om_ip)
                compute_node_roles[om_ip] = role_list
                cur_host_roles = [role for role in role_list if role.startswith("blockstorage-driver-kvm")]
                if len(cur_host_roles) >= 2:
                    continue
                selected_compute_nodes[om_ip] = host_id
                max_vbs_num -= 1
            if not selected_compute_nodes:
                err_msg = "No compute node is available, all computes role info:{}".format(compute_node_roles)
                logger.error(err_msg)
                raise HCCIException(626393)
        logger.info('Selected compute nodes: {}'.format(selected_compute_nodes))
        return selected_compute_nodes

    def multi_backend_name_config_check(self, multi_backend, cinder_cluster_data):
        if self.new_pool:
            # 新增业务存储-新增存储池场景，LLD表填写的az内应存在cinder-kvm00X
            cluster_info = self.query_cinder_driver_info_by_az_id(cinder_cluster_data, self.az_id)
            if not cluster_info:
                err_msg = 'Error: The cinder-kvm service does not exist in the az [{}]'.format(self.az_id)
                logger.error(err_msg)
                raise HCCIException(626381, self.az_id, self.az_id)
            cinder_driver_info = cluster_info["params"]["cinder_drivers"][0]["cfg"], cluster_info["params"]['host']
            return cinder_driver_info
        else:
            # 部署工程，扩AZ，IPSAN扩DistributedStorage场景，通过az_id和后端存储名不应查到cinder-kvm，即后端存储配置名称应不存在
            exist_cluster_name = dict()
            for cur_backend_name in multi_backend:
                cinder_kvm_name = self.query_cinder_kvm_by_backend_name(cinder_cluster_data, cur_backend_name)
                if cinder_kvm_name:
                    exist_cluster_name[cur_backend_name] = cinder_kvm_name
            if exist_cluster_name:
                err_msg = 'Error: the backend [{}] already exists'.format(exist_cluster_name)
                logger.error(err_msg)
                raise HCCIException(626382, exist_cluster_name)
        return ''

    def get_storage_pool_name_id_map(self):
        logger.info('Start to query storage pool')
        status_code, error_code, error_des = self.opr.login(DeployConstant.DM_LOGIN_USER, self.update_pwd)
        if status_code != 200 or error_code != 0:
            err_msg = "Failed to login deploy manager, " \
                      "Detail:[status:%s,code:%s] %s" % (status_code, error_code, error_des)
            logger.error(err_msg)
            raise HCCIException(626067, err_msg)
        logger.info("Query storage pool data.")
        res_pool = self.opr.query_storage_pool()
        pool_info = res_pool.get_query_data()
        storage_pools = pool_info.get('storagePools')
        if len(storage_pools) == 0:
            err_msg = "Failed to query storage pool information."
            logger.error(err_msg)
            self.opr.login_out(DeployConstant.DM_LOGIN_USER, self.update_pwd)
            raise HCCIException(626078, err_msg)
        pool_name_id_map = dict((cur_info.get('poolName'), cur_info.get('poolId')) for cur_info in storage_pools)
        self.opr.login_out(DeployConstant.DM_LOGIN_USER, self.update_pwd)
        logger.info('Result:{}'.format(pool_name_id_map))
        return pool_name_id_map

    def query_cinder_kvm_by_az_id_and_backend_name(self, cluster_data, availability_zone, enabled_backend):
        """
        :param cluster_data:
        :param availability_zone:
        :param enabled_backend:
        :return: cinder-kvm00x

        """
        no_value = None
        cluster_list = cluster_data.get('cluster_list')
        if not cluster_list:
            logger.info('The cinder kvm service does not exist')
            return no_value
        cinder_kvm = self._get_cinder_kvm(availability_zone, cluster_list, enabled_backend)
        if not cinder_kvm:
            logger.info('The cinder kvm service does not exist')
            return no_value
        else:
            return cinder_kvm

    def query_cinder_driver_info_by_az_id(self, cluster_data, availability_zone):
        no_value = None
        cluster_list = cluster_data.get('cluster_list')
        if not cluster_list:
            logger.info('The cinder kvm service does not exist, az id:{}'.format(availability_zone))
            return no_value
        cluster, cluster_exist_cinder_kvm = self._get_cinder_kvm_cluster(availability_zone, cluster_list)
        if cluster_exist_cinder_kvm:
            return cluster
        else:
            logger.info('The cinder kvm service does not exist, az id:{}'.format(availability_zone))
            return no_value

    def get_business_backend_count(self):
        project_conditions = get_project_conditions(self.project_id)
        backend_count = 1
        for index in range(2, DeployConstant.MAX_BUSINESS_BACKEND + 1):
            if project_conditions.get('MultiTenantFB80StoragePool{}'.format(index)):
                backend_count += 1
            else:
                break
        return backend_count

    def get_multiple_backend_section(self, pool_name_id_dict):
        section_list = list()
        multi_backend = list()
        business_backend_count = self.get_business_backend_count()
        for index in range(1, business_backend_count + 1):
            backend_x = self._param_suffix('business_enabled_backend', index)
            pool_x = self._param_suffix('business_storage_pool', index)
            rate_x = self._param_suffix('business_thin_alloc_rate', index)
            backend = self.db.get_value_from_cloudparam(self.pod_id, "DistributedStorageBusiness", backend_x)
            backend_pools = self.db.get_value_from_cloudparam(self.pod_id, "DistributedStorageBusiness", pool_x)
            over_ratio = self.db.get_value_from_cloudparam(self.pod_id, "DistributedStorageBusiness", rate_x)
            if not backend or not backend_pools or not over_ratio:
                err_msg = "Some or all backend parameters are empty. Parameters: %s:%s, %s:%s, %s:%s" \
                          % (backend_x, backend, pool_x, backend_pools, rate_x, over_ratio)
                logger.error(err_msg)
                raise HCCIException(626006, err_msg)
            logger.info("Get the index[%s] of backend info, backend_x:%s, pool_x:%s, rate_x:%s"
                        % (index, backend_x, pool_x, rate_x))
            pool_id_list = list()
            not_exist_pools = list()
            pool_name_list = backend_pools.split(',')
            for pool_name in pool_name_list:
                pool_id = pool_name_id_dict.get(pool_name)
                if pool_id is None:
                    logger.error("Not exist storage pool [%s] filled in the LLD." % pool_name)
                    not_exist_pools.append(pool_name)
                pool_id_list.append(str(pool_id))
            if len(not_exist_pools) > 0:
                err_msg = "Failed to query the storage pool ID based on the storage pool name[%s]. Exist pool:%s" \
                          % (','.join(not_exist_pools), pool_name_id_dict)
                logger.error(err_msg)
                raise HCCIException(626006, err_msg)

            section = {"volume_backend_name": backend,
                       "pool_id_list": ','.join(pool_id_list),
                       "over_ratio": over_ratio}
            section_list.append(section)
            multi_backend.append(backend)
        logger.info("backend section list: %s " % section_list)
        return section_list, multi_backend

    def transfer_uds_key(self, uds_data):
        cps_client = FSPAuthClient.get_cps_rest_client(self.db, self.project_id, self.pod_id)
        uds_service = "glance"
        usd_template = "glance"
        uds_info = cps_client.get_template_params(uds_service, usd_template)
        uds_data_ak = uds_info.get("s3_store_access_key")
        uds_data_sk = uds_info.get("s3_store_secret_key")
        first_node_ip = FSPAuthClient.get_ssh_control_ip(self.db, self.project_id, self.pod_id)
        ssh_client = self.get_fsp_ssh_client(self.pod_id, first_node_ip)
        access_key, secret_key = self._decrypt_obs(ssh_client, uds_data_ak, uds_data_sk)
        logger.info("decrypt access and secret key successfully!")
        uds_data["s3_store_access_key_cinder"] = access_key
        uds_data["s3_store_secret_key_cinder"] = secret_key

    def rollback_procedure(self):
        """
        新增业务存储-新增存储池场景：
            LLD表规划的后端名和pool_id存在：若对接的pool_id，都是LLD表存储池对应的pool_id，删后端；否则删除pool_id，不删后端
        部署工程、扩AZ、san扩fs场景：az内的cinder-kvm00X不应存在lld表填写的后端存储名。回滚查到cinder-kvm00X存在则删除
        :return:
        """
        logger.info('Query multiple backend name in the LLD')
        pool_name_id_dict = self.get_storage_pool_name_id_map()
        section_list, multi_backend = self.get_multiple_backend_section(pool_name_id_dict)

        logger.info("Get rollback params")
        webui_client = FSPAuthClient.get_cps_web_client(self.db, self.project_id, self.pod_id)
        obj = ConfinCascadingKvm(webui_client)
        resource_pool_data = obj.get_kvm_resource_pool()
        new_pool, cluster_info = self.rollback_get_multi_backend_params(
            multi_backend, resource_pool_data, section_list)

        logger.info('Execute rollback')
        if not cluster_info:
            logger.info("Rollback end")
            return
        if new_pool:
            cluster_name, enabled_backend, fs_agent, update_section_list, proxy_hosts = cluster_info
            logger.info('This is the increase storage pool scenario, update {}'.format(cluster_name))

            logger.info('Upload certificates and get private key')
            private_key_psw = self.install_opr.upload_cert_and_get_private_key(webui_client)

            logger.info('Get last uds image data')
            last_uds_data = obj.get_last_uds_image(resource_pool_data)

            logger.info('Update cinder connect')
            if last_uds_data:
                self.transfer_uds_key(last_uds_data)
                obj.update_resource_kvm_multiple_backend(
                    enabled_backend, self.float_ip, fs_agent, update_section_list, proxy_hosts, self.az_id,
                    private_key_psw, cluster_name, last_uds_data)
            else:
                obj.update_resource_kvm_multiple_backend(
                    enabled_backend, self.float_ip, fs_agent, update_section_list, proxy_hosts, self.az_id,
                    private_key_psw, cluster_name)
        else:
            logger.info('This is ExpansionAZ-KVM scenario, Delete {}'.format(cluster_info))
            obj.delete_resource(cluster_info)

        logger.info("Rollback end")

    def rollback_get_multi_backend_params(self, multi_backend, cinder_cluster_data, section_list):
        if self.new_pool:
            # 新增业务存储-新增存储池场景
            cluster_info = self.query_cinder_driver_info_by_az_id(cinder_cluster_data, self.az_id)
            if not cluster_info:
                return True, ''
            cluster_name = cluster_info["params"]['host']
            logger.info('The {} service exists in the {}'.format(cluster_name, self.az_id))
            cinder_driver_cfg = cluster_info["params"]["cinder_drivers"][0]["cfg"]
            exist_section_list = cinder_driver_cfg['section_list']
            update_section_list = self.rollback_get_section_list_while_new_pool(exist_section_list, section_list)
            if update_section_list:
                enabled_backend = cinder_driver_cfg['enabled_backend']
                fs_agent = cinder_driver_cfg['fusionstorageagent']
                proxy_hosts = cluster_info['proxy_hosts']
                return True, (cluster_name, enabled_backend, fs_agent, update_section_list, proxy_hosts)
            return True, ''
        else:
            # 部署工程、扩AZ、san扩fs场景
            backend_name = multi_backend[0]
            cluster_name = self.query_cinder_kvm_by_az_id_and_backend_name(
                cinder_cluster_data, self.az_id, backend_name)
            if cluster_name:
                logger.info('The {} service already exists'.format(cluster_name))
            return False, cluster_name

    def _config_cinder_kvm(self, *args):
        last_uds_data, obj,\
            enabled_backend, fs_agent, section_list,\
            compute_id_list, private_key_psw, cluster_name = args
        logger.info("Start to config Cinder connect with DistributedStorage.")
        if not last_uds_data:
            logger.info("Config the image type with glance")
            if self.new_pool:
                logger.info("Update Cinder connect with DistributedStorage")
                obj.update_resource_kvm_multiple_backend(
                    enabled_backend, self.float_ip, fs_agent, section_list, compute_id_list, self.az_id,
                    private_key_psw, cluster_name)
            else:
                logger.info("Config Cinder connect with DistributedStorage")
                obj.config_resource_kvm_multiple_backend(
                    enabled_backend, self.float_ip, fs_agent, section_list, compute_id_list, self.az_id,
                    private_key_psw)
        else:
            self.transfer_uds_key(last_uds_data)
            logger.info("Config the image type with uds")
            if self.new_pool:
                obj.update_resource_kvm_multiple_backend(
                    enabled_backend, self.float_ip, fs_agent, section_list, compute_id_list, self.az_id,
                    private_key_psw, cluster_name, last_uds_data)
            else:
                obj.config_kvm_multiple_backend_with_obs(
                    enabled_backend, self.float_ip, fs_agent, section_list, compute_id_list, self.az_id,
                    last_uds_data, private_key_psw)

    def _get_cinder_kvm(self, availability_zone, cluster_list, enabled_backend):
        cinder_kvm = None
        for cluster in cluster_list:
            cinder_drivers = cluster["params"]["cinder_drivers"]
            if not cinder_drivers:
                continue
            backend_store = cinder_drivers[0]["backend_store"]
            cur_az = cinder_drivers[0]["cfg"]["availability_zone"]
            if backend_store != 'fusionstorage' or cur_az != availability_zone:
                continue
            section_list = cinder_drivers[0]["cfg"]['section_list']
            for section in section_list:
                if section['volume_backend_name'] == enabled_backend:
                    cinder_kvm = cluster["params"]["host"]
                    logger.info('availability zone:{}, backend name:{}, exist cinder-kvm:{}'.format(
                        availability_zone, enabled_backend, cinder_kvm))
        return cinder_kvm

    def _get_cinder_kvm_cluster(self, availability_zone, cluster_list):
        cluster_exist_cinder_kvm = False
        target_cluster = None
        for cluster in cluster_list:
            cinder_drivers = cluster["params"]["cinder_drivers"]
            if not cinder_drivers:
                continue
            backend_store = cinder_drivers[0]["backend_store"]
            cur_az = cinder_drivers[0]["cfg"]["availability_zone"]
            if backend_store == 'fusionstorage' and cur_az == availability_zone:
                cinder_kvm = cluster["params"]["host"]
                logger.info('availability zone:{}, exist cinder-kvm:{}'.format(availability_zone, cinder_kvm))
                cluster_exist_cinder_kvm = True
                target_cluster = cluster
                break
        return target_cluster, cluster_exist_cinder_kvm