package com.bocloud.ims.service.resource;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.compute.ClusterDriver;
import com.bocloud.cmp.driver.compute.HostAggregateDriver;
import com.bocloud.cmp.driver.compute.HostDriver;
import com.bocloud.cmp.driver.compute.ResourcePoolDriver;
import com.bocloud.cmp.driver.monitor.MonitorDriver;
import com.bocloud.cmp.entity.enums.*;
import com.bocloud.cmp.model.ClusterBean;
import com.bocloud.cmp.model.ClusterModel;
import com.bocloud.cmp.model.ClusterOperateModel;
import com.bocloud.cmp.model.HostOperateModel;
import com.bocloud.cmp.model.powervc.PowervcConstant;
import com.bocloud.common.enums.BoCloudService;
import com.bocloud.common.model.*;
import com.bocloud.common.utils.*;
import com.bocloud.ims.common.utils.DateUtils;
import com.bocloud.ims.entity.common.VendorSyncRecord;
import com.bocloud.ims.entity.resource.*;
import com.bocloud.ims.interfaces.resource.ClusterService;
import com.bocloud.ims.repository.pbm.PbmProfileRepository;
import com.bocloud.ims.repository.resource.*;
import com.bocloud.ims.service.model.cmdb.CmdbInfo;
import com.bocloud.ims.service.model.cmdb.CmdbRelation;
import com.bocloud.ims.service.task.ResourceTaskNotice;
import com.bocloud.ims.service.transporter.vendor.VmwareTransporter;
import com.bocloud.ims.service.transportor.SingleVmwareTransportor;
import com.bocloud.ims.service.utils.*;
import com.bocloud.service.lock.BocloudACLock;
import com.bocloud.service.lock.LockFactory;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service("clusterService")
public class ClusterServiceImpl implements ClusterService {

    private static final Logger logger = LoggerFactory.getLogger(ClusterServiceImpl.class);
    @Autowired
    private ClusterRepository clusterRepository;
    @Autowired
    private LockFactory lockFactory;
    @Autowired
    private CloudVendorRepository cloudVendorRepository;
    @Autowired
    private ClusterDriver clusterDriver;
    @Autowired
    private HostDriver hostDriver;
    @Autowired
    private ServerRepository serverRepository;
    @Autowired
    private CloudServerRepository cloudServerRepository;
    @Autowired
    private SnapshotRepository snapshotRepository;
    @Autowired
    private ResourceEventPublisher resourceEventPublisher;
    @Autowired
    private ClusterNodeRepository clusterNodeRepository;
    @Autowired
    private ServerConfigRepository serverConfigRepository;
    @Autowired
    private ResourcePoolRepository resourcePoolRepository;
    @Autowired
    private VdcRepository vdcRepository;
    @Autowired
    private AlarmThresholdRepository alarmThresholdRepository;
    @Autowired
    private ResourcePoolDriver resourcePoolDriver;
    @Autowired
    private CmdbMessagePublisher cmdbMessagePublisher;
    @Autowired
    private HostAggregateDriver hostAggregateDriver;
    @Autowired
    private RegionRepository regionRepository;
    @Autowired
    private PoolGroupRelationRepository poolGroupRelationRepository;
    @Autowired
    private MonitorDriver monitorDriver;
    @Autowired
    private ClusterUsageRepository clusterUsageRepository;
    @Autowired
    private DataStoreRepository dataStoreRepository;
    @Autowired
    private NetworkRepository networkRepository;
    @Autowired
    private NetworkCardRepository networkCardRepository;
    @Autowired
    private SwitcherRepository switcherRepository;
    @Autowired
    private PortGroupRepository portGroupRepository;
    @Autowired
    private IpPoolPortGroupRepository ipPoolPortGroupRepository;
    @Autowired
    private StoreHostRepository storeHostRepository;
    @Autowired
    private NetworkHostRepository networkHostRepository;
    @Autowired
    private ServerAssetsRepository serverAssetsRepository;
    @Autowired
    private ScsiLunRepository scsiLunRepository;
    @Autowired
    private PbmProfileRepository profileRepository;
    @Autowired
    private ResourceRepository resourceRepository;
    @Autowired
    private IpRepository ipRepository;
    @Autowired
    private IpPoolRepository ipPoolRepository;
    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    private VmwareTransporter vmwareTransporter;
    @Autowired
    private ResourceTaskNotice resourceTaskNotice;

    /**
     * @since 2018-04-25 modify by sxp 增加统计CPU、内存、磁盘使用情况
     */
    @Override
    public BocloudResult<GridBean<Cluster>> list(Pager pager) {
        GridBean gridBean = null;
        try {
            pager.getSorter().put("gmtCreate", Common.ONE);
            int total = this.clusterRepository.count(pager.getParams());
            if (pager.getSimple()) {
                List<SimpleBean> beans = this.clusterRepository.list(pager.getParams(), pager.getSorter());
                gridBean = new GridBean(1, 1, total, beans);
            } else {
                List<Cluster> list = this.clusterRepository.list(pager.getPage(), pager.getRows(), pager.getParams(), pager.getSorter());
                for (Cluster cluster : list) {
                    // if (!CloudProvider.OPENSTACK.name().equals(cluster.getType())) {
                    // // 计算集群的资源信息
                    // cmpResourceInfo(cluster);
                    // }
                    if (CloudProvider.VMWARE.name().equals(cluster.getType())) {
                        // 计算可分配量
                        calDistributable(cluster);
                    } else {
                        List<Server> servers = serverRepository.listByCluster(cluster.getId());
                        cluster.setHostNum(servers.size());
                        cluster.setVmNum(cloudServerRepository.countByClusterId(cluster.getId(), false));
                        cluster.setTemplateNum(cloudServerRepository.countByClusterId(cluster.getId(), true));
                        List<Long> hostIds = new ArrayList<>();
                        for (Server server : servers) {
                            hostIds.add(server.getId());
                        }
                        List<ServerConfig> configs = new ArrayList<>();
                        if (!ListTool.isEmpty(hostIds)) {
                            configs = serverConfigRepository.listByHostIds(hostIds);
                        }
                        Map<Long, ServerConfig> configMap = new HashMap<>();
                        for (ServerConfig config : configs) {
                            configMap.put(config.getServerId(), config);
                        }
                        Integer cpuCore = 0;
                        for (Server server : servers) {
                            ServerConfig config = configMap.get(server.getId());
                            if (null == config) {
                                continue;
                            }
                            cpuCore += null == config.getCpuCore() ? 0 : config.getCpuCore();
                        }
                        cluster.setCpuCore(cpuCore);
                        Long cpuTotal = null == cluster.getCpuTotal() ? 0L : cluster.getCpuTotal();
                        Long cpuUsed = null == cluster.getCpuUsed() ? 0L : cluster.getCpuUsed();
                        Double memTotal = null == cluster.getMemTotal() ? 0.0 : cluster.getMemTotal();
                        Double memUsed = null == cluster.getMemUsed() ? 0.0 : cluster.getMemUsed();
                        Double diskTotal = null == cluster.getDiskTotal() ? 0.0 : cluster.getDiskTotal();
                        Double diskUsed = null == cluster.getDiskUsed() ? 0.0 : cluster.getDiskUsed();
                        cluster.setCpuUnused(cpuTotal - cpuUsed);
                        cluster.setMemUnused(BigDecimal.valueOf(memTotal - memUsed)
                                .setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
                        cluster.setDiskUnused(BigDecimal.valueOf(diskTotal - diskUsed)
                                .setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
                    }
                    if (CloudProvider.POWERVC.name().equals(cluster.getType())) {
                        // 计算主机数
                        calServerCount(cluster);
                    }
                }
                gridBean = GridHelper.getBean(pager.getPage(), pager.getRows(), total, list);
            }
            return new BocloudResult<>(true, gridBean, "查询成功");
        } catch (Exception e) {
            logger.error("Query cluster list fail:", e);
            return new BocloudResult<>(false, "查询失败");
        }
    }

    /**
     * 计算集群可分配量
     *
     * @param cluster
     */
    private void calDistributable(Cluster cluster) throws Exception {
        // 集群下无宿主机的话直接跳过
        List<Server> servers = serverRepository.listByCluster(cluster.getId());
        List<Long> hostIds = new ArrayList<>();
        for (Server server : servers) {
            hostIds.add(server.getId());
        }
        List<ServerConfig> configs = new ArrayList<>();
        if (!ListTool.isEmpty(hostIds)) {
            configs = serverConfigRepository.listByHostIds(hostIds);
        }
        Map<Long, ServerConfig> configMap = new HashMap<>();
        for (ServerConfig config : configs) {
            configMap.put(config.getServerId(), config);
        }
        cluster.setHostNum(servers.size());
        cluster.setVmNum(cloudServerRepository.countByClusterId(cluster.getId(), false));
        cluster.setTemplateNum(cloudServerRepository.countByClusterId(cluster.getId(), true));
        Long cpuExcessRatio = cluster.getCpuExcessRatio();
        BigDecimal cpuDistributableRatio = cluster.getCpuDistributableRatio();
        BigDecimal memDistributableRatio = cluster.getMemDistributableRatio();
        if (null == cpuExcessRatio || null == cpuDistributableRatio || null == memDistributableRatio) {
            cluster.setCpuDistributable(0);
            cluster.setMemDistributable(0D);
            return;
        }
        if (ListTool.isEmpty(servers)) {
            cluster.setCpuDistributable(0);
            cluster.setMemDistributable(0D);
            return;
        }
        // cpu可分配容量
        BigDecimal cpuDistributable = BigDecimal.valueOf(0);
        // 内存可分配容量
        BigDecimal memDistributable = BigDecimal.valueOf(0);
        List<CloudServer> vms = cloudServerRepository.listByHostIds(hostIds);
        if (ListTool.isEmpty(vms)) {
            vms = new ArrayList<CloudServer>();
        }
        Integer cpuCore = 0;
        Integer vmCpuTotal = 0;
        for (Server server : servers) {
            ServerConfig config = configMap.get(server.getId());
            if (null == config) {
                continue;
            }
            cpuCore += null == config.getCpuCore() ? 0 : config.getCpuCore();
            // 云主机已使用的CPU和内存总量
            int cpu = 0;
            double memory = 0;
            for (CloudServer vm : vms) {
                if (server.getId().equals(vm.getHostId())) {
                    // 停止的云主机不参与统计
                    cpu += vm.getCpu() == null ? 0 : vm.getCpu();
                    memory += null == vm.getMemory() ? 0 : vm.getMemory().doubleValue();
                }
            }
            vmCpuTotal += cpu;
            // cpu核芯数*超分比*可分配阈值
            BigDecimal cpuDist = BigDecimal.valueOf(null == config.getCpuCore() ? 0 : config.getCpuCore())
                    .multiply(BigDecimal.valueOf(null == cpuExcessRatio ? 0L : cpuExcessRatio))
                    .multiply(null == cpuDistributableRatio ? BigDecimal.valueOf(0) : cpuDistributableRatio)
                    .divide(BigDecimal.valueOf(100)).subtract(BigDecimal.valueOf(cpu));
            if (cpuDist.intValue() > 0) {
                cpuDistributable = cpuDistributable.add(cpuDist);
            }
            // 内存总量*可分配阈值
            BigDecimal memDist = BigDecimal.valueOf(null == config.getMemoryCapacity() ? 0 : config.getMemoryCapacity())
                    .multiply(null == memDistributableRatio ? BigDecimal.valueOf(0L) : memDistributableRatio)
                    .divide(BigDecimal.valueOf(100)).subtract(BigDecimal.valueOf(memory));
            if (memDist.intValue() > 0) {
                memDistributable = memDistributable.add(memDist);
            }
        }
        cluster.setVmCpuTotal(vmCpuTotal);
        cluster.setCpuCore(cpuCore);
        cluster.setCpuDistributable(cpuDistributable.intValue());
        cluster.setMemDistributable(memDistributable.doubleValue());
        Long cpuTotal = null == cluster.getCpuTotal() ? 0L : cluster.getCpuTotal();
        Long cpuUsed = null == cluster.getCpuUsed() ? 0L : cluster.getCpuUsed();
        Double memTotal = null == cluster.getMemTotal() ? 0.0 : cluster.getMemTotal();
        Double memUsed = null == cluster.getMemUsed() ? 0.0 : cluster.getMemUsed();
        Double diskTotal = null == cluster.getDiskTotal() ? 0.0 : cluster.getDiskTotal();
        Double diskUsed = null == cluster.getDiskUsed() ? 0.0 : cluster.getDiskUsed();
        cluster.setCpuUnused(cpuTotal - cpuUsed);
        cluster.setMemUnused(
                BigDecimal.valueOf(memTotal - memUsed).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
        cluster.setDiskUnused(
                BigDecimal.valueOf(diskTotal - diskUsed).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
    }

    /**
     * 计算集群中的主机个数
     *
     * @param cluster
     */
    private void calServerCount(Cluster cluster) throws Exception {
        List<Server> servers = serverRepository.listByCluster(cluster.getId());
        cluster.setHostNum(servers.size());
    }

    @Override
    public BocloudResult<Cluster> create(ClusterOperateModel model, RequestContext context) {
        try {
            CloudVendor vendor = cloudVendorRepository.query(model.getVendorId());
            Assert.notNull(vendor, "获取云供应商失败");
            if (CloudProvider.OPENSTACK.name().equals(vendor.getType())||CloudProvider.EASYSTACK.name().equals(vendor.getType())) {
                ClusterModel clusterModel = new ClusterModel();
                clusterModel.setName(model.getClusterName());
                Region region = regionRepository.query(model.getRegionId());
                Assert.notNull(region, "所属域不存在");
                clusterModel.setRegion(region.getName());
                BocloudResult result = hostAggregateDriver.create(clusterModel, vendor.getUuid(), null);
                Assert.isTrue(result.isSuccess(), "主机组创建失败:" + result.getMessage());
                Cluster cluster = new Cluster();
                ClusterModel cluModel = JSONObject.parseObject(JSONObject.toJSONString(result.getData()),
                        ClusterModel.class);
                BeanUtils.copyProperties(cluModel, cluster);
                cluster.setCreatorId(context.getTarget());
                cluster.setGmtCreate(new Date());
                cluster.setVendorId(vendor.getId());
                cluster.setType(vendor.getType());
                cluster.setRegionId(region.getId());
                clusterRepository.save(cluster);
                return new BocloudResult<>(true, "主机组创建成功");
            }
            if (CloudProvider.POWERVC.name().equals(vendor.getType())) {
                ClusterModel clusterModel = new ClusterModel();
                // 检查名称是否存在
                Cluster clusterByName = clusterRepository.queryByName(model.getClusterName(), vendor.getId());
                Assert.isNull(clusterByName, "该主机组名称已经存在");
                clusterModel.setName(model.getClusterName());
                // 检查布置策略是否合法
                Integer initialPolicyId = PowervcOsAggregateInitialPolicy.getId(model.getInitialPolicy());
                Assert.notNull(initialPolicyId, "该布置策略无效");
                clusterModel.setInitialPolicy(model.getInitialPolicy());
                // 检查主机组中的主机是否已经被分配到了别的组
                List<Server> servers = new ArrayList<>();
                if (model.getHostNames() != null) {
                    for (String hostName : model.getHostNames()) {
                        Server server = serverRepository.getByHostName(hostName, vendor.getId());
                        if (server == null) {
                            return new BocloudResult<>(false, "未找到主机：" + hostName);
                        }
                        Cluster defaultCluster = clusterRepository.queryByUuid(PowervcConstant.DEFAULT_OS_AGGREGATE_ID,
                                vendor.getId());
                        if (defaultCluster == null) {
                            return new BocloudResult<>(false, "缺省主机组：Default Group");
                        }
                        if (!server.getClusterId().equals(defaultCluster.getId())) {
                            return new BocloudResult<>(false, "主机[" + hostName + "]已经被分到了其他主机组");
                        }
                        servers.add(server);
                    }
                }
                clusterModel.setHostNames(model.getHostNames());
                BocloudResult result = hostAggregateDriver.create(clusterModel, vendor.getUuid(), null);
                Assert.isTrue(result.isSuccess(), "主机组创建失败:" + result.getMessage());
                ClusterModel cluModel = (ClusterModel) result.getData();
                Cluster cluster = new Cluster();
                BeanUtils.copyProperties(cluModel, cluster);
                cluster.setCreatorId(context.getTarget());
                cluster.setGmtCreate(new Date());
                cluster.setVendorId(vendor.getId());
                clusterRepository.save(cluster);
                // 调整主机组中的主机
                for (Server server : servers) {
                    server.setClusterId(cluster.getId());
                    serverRepository.update(server);
                }
                return new BocloudResult<>(true, "主机组创建成功");
            }
            Vdc vdc = vdcRepository.query(model.getVdcId());
            Assert.notNull(vdc, "数据中心不存在");
            boolean flag = clusterRepository.exists(model.getClusterName(), vdc.getId());
            Assert.isTrue(flag, "该集群名称已存在");
            model.setVdcName(vdc.getName());
            new Thread(() -> {
                String operate = vendor.getType().toLowerCase() + ".cluster";
                String msgContent = "集群创建失败";
                BocloudResult result = clusterDriver.create(vendor.getUuid(), model);
                try {
                    if (result.isSuccess()) {
                        msgContent = "集群创建成功";
                        // 同步集群
                        String content = JSONObject.toJSONString(result.getData());
                        Cluster cluster = JSONObject.parseObject(content, Cluster.class);
                        cluster.setType(CloudProvider.VMWARE.name());
                        cluster.setUuid(IDFactory.instance().uuid());
                        cluster.preSave(context.getTarget(), context.getTarget(), vendor.getId(), model.getVdcId());
                        clusterRepository.save(cluster);
                        // 保存资源池
                        VmResourcePool vmResourcePool = cluster.getResourcePool();
                        if (null != vmResourcePool) {
                            vmResourcePool.setParentId(0L);
                            vmResourcePool.setVdcId(cluster.getVdcId());
                            vmResourcePool.setOwner(cluster.getId());
                            vmResourcePool.setOwnerCategory("CLUSTER");
                            vmResourcePool.setVendorId(vendor.getId());
                            vmResourcePool.setTenantId(0L);
                            vmResourcePool.setCreatorId(context.getTarget());
                            resourcePoolRepository.save(vmResourcePool);
                        }
                        // 同步到cmdb
                        List<CmdbInfo> infos = Lists.newArrayList();
                        List<CmdbRelation> relations = Lists.newArrayList();
                        relations.add(new CmdbRelation(ModuleCode.VDC.name(), 1L, ListUtils.getList(vdc.getGuid())));
                        infos.add(CmdbInfoConvertor.getInfo(cluster, null, relations));
                        cmdbMessagePublisher.send(CmdbInfoConvertor.getModel(BoCloudService.IMS, infos));
                    }
                    resourceEventPublisher.send(new OperateResult(result.isSuccess(), msgContent, operate,
                            MapTools.simpleMap("vendorId", vendor.getId()), OperateResult.OperateCategory.ResourceEvent,
                            context));
                } catch (Exception e) {
                    logger.error("Get error message:", e);
                    resourceEventPublisher.send(new OperateResult(result.isSuccess(), msgContent, operate,
                            MapTools.simpleMap("vendorId", vendor.getId()), OperateResult.OperateCategory.ResourceEvent,
                            context));
                }
            }).start();
            return new BocloudResult<>(true, "集群创建任务已下发，正在执行...");
        } catch (Exception e) {
            logger.error("create cluster error", e);
            return new BocloudResult<>(false, "创建集群失败 : " + e.getMessage());
        }
    }

    @Override
    public BocloudResult<Cluster> modify(ClusterBean bean, RequestContext context) {
        String path = Cluster.class.getSimpleName() + "_" + bean.getId();
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            Cluster cluster = this.clusterRepository.query(bean.getId());
            Assert.notNull(cluster, "数据不存在");
            CloudVendor vendor = cloudVendorRepository.query(cluster.getVendorId());
            Assert.notNull(vendor, "云平台不存在");
            Long cpuExcessRatio = bean.getCpuExcessRatio();
            BigDecimal cpuDistributableRatio = bean.getCpuDistributableRatio();
            BigDecimal memDistributableRatio = bean.getMemDistributableRatio();
            cluster.setMenderId(context.getTarget());
            if (null != cpuExcessRatio) {
                cluster.setCpuExcessRatio(cpuExcessRatio);
                this.clusterRepository.update(cluster);
                return new BocloudResult<>(true, "修改成功");
            } else if (null != cpuDistributableRatio || null != memDistributableRatio) {
                cluster.setCpuDistributableRatio(cpuDistributableRatio);
                cluster.setMemDistributableRatio(memDistributableRatio);
                this.clusterRepository.update(cluster);
                return new BocloudResult<>(true, "修改成功");
            }
            if (!bean.getName().equals(cluster.getName())) {
                boolean flag;
                if (CloudProvider.POWERVC.name().equals(vendor.getType())) {
                    flag = clusterRepository.queryByName(bean.getName(), vendor.getId()) == null;
                } else {
                    flag = clusterRepository.exists(bean.getName(), cluster.getVdcId());
                }
                if (!flag) {
                    return new BocloudResult<>(false, "该名称已存在");
                }
            }
            if (CloudProvider.OPENSTACK.name().equals(vendor.getType())||CloudProvider.EASYSTACK.name().equals(vendor.getType())) {
                ClusterModel clusterModel = new ClusterModel();
                clusterModel.setName(bean.getName());
                Region region = regionRepository.query(bean.getRegionId());
                Assert.notNull(region, "所属域不存在");
                clusterModel.setUuid(cluster.getUuid());
                clusterModel.setRegion(region.getName());
                BocloudResult result = hostAggregateDriver.modify(clusterModel, vendor.getUuid(), null);
                Assert.isTrue(result.isSuccess(), "主机组修改失败:" + result.getMessage());
                ClusterModel cluModel = JSONObject.parseObject(JSONObject.toJSONString(result.getData()),
                        ClusterModel.class);
                BeanUtils.copyProperties(cluModel, cluster);
                cluster.setRegionId(region.getId());
                cluster.setMenderId(context.getTarget());
                cluster.setGmtModify(new Date());
                cluster.setType(vendor.getType());
                clusterRepository.update(cluster);
                return new BocloudResult<>(true, "主机组修改成功");
            }
            if (CloudProvider.POWERVC.name().equals(vendor.getType())) {
                ClusterModel clusterModel = new ClusterModel();
                clusterModel.setUuid(cluster.getUuid());
                clusterModel.setName(bean.getName());
                // 检查布置策略是否合法
                Integer initialPolicyId = PowervcOsAggregateInitialPolicy.getId(bean.getInitialPolicy());
                Assert.notNull(initialPolicyId, "该布置策略无效");
                clusterModel.setInitialPolicy(bean.getInitialPolicy());
                // 检查主机组中的主机是否已经被分配到了别的组
                List<Server> newServers = new ArrayList<>();
                if (bean.getHostNames() != null) {
                    for (String hostName : bean.getHostNames()) {
                        Server server = serverRepository.getByHostName(hostName, vendor.getId());
                        Assert.notNull(server, "未找到主机：" + hostName);
                        Cluster defaultCluster = clusterRepository.queryByUuid(PowervcConstant.DEFAULT_OS_AGGREGATE_ID,
                                vendor.getId());
                        Assert.notNull(defaultCluster, "缺省主机组：Default Group");
                        if (!server.getClusterId().equals(defaultCluster.getId())
                                && !server.getClusterId().equals(cluster.getId())) {
                            return new BocloudResult<>(false, "主机[" + hostName + "]已经被分到了其他主机组");
                        }
                        newServers.add(server);
                    }
                }
                clusterModel.setHostNames(bean.getHostNames());
                // 调用driver开始处理
                BocloudResult result = hostAggregateDriver.modify(clusterModel, vendor.getUuid(), null);
                Assert.isTrue(result.isSuccess(), "主机组修改失败:" + result.getMessage());
                ClusterModel cluModel = (ClusterModel) result.getData();
                BeanUtils.copyProperties(cluModel, cluster);
                cluster.setMenderId(context.getTarget());
                cluster.setGmtModify(new Date());
                clusterRepository.update(cluster);
                // 处理主机所属主机组
                Cluster defaultCluster = clusterRepository.queryByUuid(PowervcConstant.DEFAULT_OS_AGGREGATE_ID,
                        vendor.getId());
                Assert.notNull(defaultCluster, "主机组修改失败:未找到缺省主机组[Default Group]");
                List<Server> oldServers = serverRepository.listByCluster(cluster.getId());
                for (Server newServer : newServers) {
                    boolean findInOldServers = false;
                    for (Server oldServer : oldServers) {
                        if (newServer.getId().equals(oldServer.getId())) {
                            findInOldServers = true;
                            break;
                        }
                    }
                    if (!findInOldServers) {
                        newServer.setClusterId(cluster.getId());
                        serverRepository.update(newServer);
                    }
                }
                for (Server oldServer : oldServers) {
                    boolean findInNewServers = false;
                    for (Server newServer : newServers) {
                        if (oldServer.getId().equals(newServer.getId())) {
                            findInNewServers = true;
                        }
                    }
                    if (!findInNewServers) {
                        oldServer.setClusterId(defaultCluster.getId());
                        serverRepository.update(oldServer);
                    }
                }
                return new BocloudResult<>(true, "主机组修改成功");
            }
            BeanUtils.copyProperties(bean, cluster);
            cluster.setMenderId(context.getTarget());
            this.clusterRepository.update(cluster);
            return new BocloudResult<>(true, cluster, "修改成功");
        } catch (Exception e) {
            logger.error("Modify cluster fail:", e);
            return new BocloudResult<>(false, "修改失败");
        }
    }

    @Override
    public BocloudResult remove(Long id, RequestContext context) {
        String path = Cluster.class.getSimpleName() + "_" + id;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            Cluster cluster = this.clusterRepository.query(id);
            Assert.notNull(cluster, "数据不存在");
            CloudVendor vendor = this.cloudVendorRepository.query(cluster.getVendorId());
            Assert.notNull(vendor, "获取云供应商失败");
            if (CloudProvider.VMWARE.name().equals(vendor.getType())) {
                List<Server> servers = serverRepository.listByCluster(id);
                if (!ListTool.isEmpty(servers)) {
                    return new BocloudResult<>(false, "集群下存在宿主机，请先移除");
                }
            }
            if (CloudProvider.OPENSTACK.name().equals(vendor.getType())||CloudProvider.EASYSTACK.name().equals(vendor.getType())) {
                List<ClusterNode> listByCluster = clusterNodeRepository.listByCluster(id);
                if (!ListTool.isEmpty(listByCluster)) {
                    return new BocloudResult<>(false, "该主机组下存在主机，无法删除");
                }
                BocloudResult result = hostAggregateDriver.remove(cluster.getUuid(), vendor.getUuid(), null);
                if (result.isFailed()) {
                    return new BocloudResult<>(false, "主机组删除失败:" + result.getMessage());
                }
                clusterRepository.remove(id, context.getTarget());
                return new BocloudResult<>(true, "主机组删除成功");
            }
            if (CloudProvider.POWERVC.name().equals(vendor.getType())) {
                BocloudResult result = hostAggregateDriver.remove(cluster.getUuid(), vendor.getUuid(), null);
                if (result.isFailed()) {
                    return new BocloudResult<>(false, "主机组删除失败:" + result.getMessage());
                }
                clusterRepository.remove(id, context.getTarget());
                Cluster defaultCluster = clusterRepository.queryByUuid(PowervcConstant.DEFAULT_OS_AGGREGATE_ID,
                        vendor.getId());
                if (defaultCluster == null) {
                    return new BocloudResult<>(false, "主机组删除失败:未找到缺省主机组[Default Group]");
                }
                List<Server> servers = serverRepository.listByCluster(id);
                for (Server server : servers) {
                    server.setClusterId(defaultCluster.getId());
                    serverRepository.update(server);
                }
                return new BocloudResult<>(true, "主机组删除成功");
            }

            new Thread(() -> {
                // 删除vmware上的集群
                ClusterOperateModel model = new ClusterOperateModel();
                model.setClusterName(cluster.getName());
                model.setVdcName(cluster.getVdcName());
                String operate = vendor.getType().toLowerCase() + ".cluster";
                BocloudResult result = clusterDriver.remove(vendor.getUuid(), model);
                if (result.isSuccess()) {
                    // 同步到cmdb
                    try {
                        // 查出集群下的宿主机
                        List<Server> hosts1 = serverRepository.listByCluster(id);
                        for (Server host : hosts1) {
                            // 查出宿主机下的云主机
                            List<CloudServer> servers = cloudServerRepository.listByHid(host.getId());
                            for (CloudServer server : servers) {
                                // 删除宿主机下的快照
                                snapshotRepository.removeByVm(server.getId(), context.getTarget());
                            }
                            // 删除宿主机下的云主机
                            cloudServerRepository.removeByHost(host.getId(), context.getTarget());
                            //通知主机资源
                            resourceTaskNotice.sendLogicalMessage(servers, ResourceTaskNotice.Action.DEL);
                        }
                        // 删除集群下的宿主机
                        List<Server> servers = serverRepository.listByCluster(id);
                        serverRepository.deleteByCluster(id, context.getTarget());
                        //通知主机资源
                        resourceTaskNotice.sendPhysicalMessage(servers, ResourceTaskNotice.Action.DEL);
                        // 删除集群下的节点
                        clusterNodeRepository.removeByCluster(id, context.getTarget());
                        clusterRepository.remove(id, context.getTarget());
                        alarmThresholdRepository.removeByTarget(id, AlarmTargetCatalog.CLUSTER.name());
                        // 删除集群下的资源池信息
                        resourcePoolRepository.removeByOwner(id, "CLUSTER", context.getTarget());
                        // 发送至cmdb
                        List<CmdbInfo> infos = Lists.newArrayList();
                        infos.add(CmdbInfoConvertor.getInfo(cluster, "delete", null));
                        cmdbMessagePublisher.send(CmdbInfoConvertor.getModel(BoCloudService.IMS, infos));
                    } catch (Exception e) {
                        logger.error("删除集群失败", e);
                        resourceEventPublisher.send(new OperateResult(false, "集群删除失败", operate,
                                MapTools.simpleMap("vendorId", vendor.getId()),
                                OperateResult.OperateCategory.ResourceEvent, context));
                        return;
                    }
                }
                resourceEventPublisher.send(new OperateResult(result.isSuccess(), result.getMessage(), operate,
                        MapTools.simpleMap("vendorId", vendor.getId()), OperateResult.OperateCategory.ResourceEvent,
                        context));
            }).start();
            return new BocloudResult<>(true, "删除任务已下发，正在执行...");
        } catch (Exception e) {
            logger.error("Remove cluster error:", e);
            return new BocloudResult<>(false, "删除失败");
        }
    }

    /**
     * @since 2018-04-25 modify by sxp 将统计宿主机数量、CPU、内存、磁盘等信息的代码抽取为独立方法
     */
    @Override
    public BocloudResult<Cluster> detail(Long id) {
        try {
            Cluster cluster = this.clusterRepository.query(id);
            if (null == cluster) {
                return new BocloudResult<>(false, "数据不存在");
            }
            if (CloudProvider.VMWARE.name().equals(cluster.getType())) {
                // 计算可分配量
                calDistributable(cluster);
            } else {
                List<Server> servers = serverRepository.listByCluster(cluster.getId());
                cluster.setHostNum(servers.size());
                cluster.setVmNum(cloudServerRepository.countByClusterId(cluster.getId(), false));
                cluster.setTemplateNum(cloudServerRepository.countByClusterId(cluster.getId(), true));
                List<Long> hostIds = new ArrayList<>();
                for (Server server : servers) {
                    hostIds.add(server.getId());
                }
                List<ServerConfig> configs = new ArrayList<>();
                if (!ListTool.isEmpty(hostIds)) {
                    configs = serverConfigRepository.listByHostIds(hostIds);
                }
                Map<Long, ServerConfig> configMap = new HashMap<>();
                for (ServerConfig config : configs) {
                    configMap.put(config.getServerId(), config);
                }
                Integer cpuCore = 0;
                for (Server server : servers) {
                    ServerConfig config = configMap.get(server.getId());
                    if (null == config) {
                        continue;
                    }
                    cpuCore += null == config.getCpuCore() ? 0 : config.getCpuCore();
                }
                cluster.setCpuCore(cpuCore);
                Long cpuTotal = null == cluster.getCpuTotal() ? 0L : cluster.getCpuTotal();
                Long cpuUsed = null == cluster.getCpuUsed() ? 0L : cluster.getCpuUsed();
                Double memTotal = null == cluster.getMemTotal() ? 0.0 : cluster.getMemTotal();
                Double memUsed = null == cluster.getMemUsed() ? 0.0 : cluster.getMemUsed();
                Double diskTotal = null == cluster.getDiskTotal() ? 0.0 : cluster.getDiskTotal();
                Double diskUsed = null == cluster.getDiskUsed() ? 0.0 : cluster.getDiskUsed();
                cluster.setCpuUnused(cpuTotal - cpuUsed);
                cluster.setMemUnused(
                        BigDecimal.valueOf(memTotal - memUsed).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
                cluster.setDiskUnused(
                        BigDecimal.valueOf(diskTotal - diskUsed).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
            }
//			if (!CloudProvider.OPENSTACK.name().equals(cluster.getType())) {
//				// 计算集群的资源信息
//				cmpResourceInfo(cluster);
//			}
            return new BocloudResult<>(true, cluster, "查询详情成功");
        } catch (Exception e) {
            logger.error("Get cluster error：", e);
            return new BocloudResult<>(false, "查询详情失败");
        }
    }

    /**
     * 计算集群的资源信息
     *
     * @author sxp
     * @since Apr 25, 2018
     * @since 2018-04-26 modify by sxp 优先使用实时数据
     * @since 2018-04-26 modify by sxp 删除使用实时数据的代码
     * @since 2018-05-18 modify by sxp 磁盘容量求和之后四舍五入保留两位小数
     */
    private void cmpResourceInfo(Cluster cluster) throws Exception {
        CloudVendor vendor = cloudVendorRepository.query(cluster.getVendorId());
        if (null == vendor) {
            return;
        }
        BocloudResult result = clusterDriver.detail(vendor.getUuid(), cluster.getClusterVal());
        if (result.isFailed()) {
            return;
        }
        ClusterModel model = JSONObject.parseObject(JSONObject.toJSONString(result.getData()), ClusterModel.class);
        Long clusterId = cluster.getId();
        List<Param> params = new ArrayList<>(1);
        params.add(new Param(MapTools.simpleMap("clusterId", clusterId), Sign.EQ));
        List<SimpleBean> hosts = serverRepository.list(params, null, null);
        int vmNum = 0, templateNum = 0, cpuCore = 0;
        Long cpuTotal = 0L, cpuUsed = 0L;
        Double diskTotal = 0D, diskUsed = 0D, memTotal = 0D, memUsed = 0D;
        Integer vmCpu, vmCpuNum, serverCpuNum;
        ServerConfig config;
        List<CloudServer> vms;
        for (SimpleBean host : hosts) {
            params.clear();
            params.add(new Param(MapTools.simpleMap("hostId", host.getId()), Sign.EQ));
            vmNum += cloudServerRepository.count(params, 0L);
            params.add(new Param(MapTools.simpleMap("isTemplate", 1), Sign.EQ));
            templateNum += cloudServerRepository.count(params, 0L);
            config = serverConfigRepository.getBySid(host.getId());
            if (config != null) {
                cpuTotal += null == config.getCpuHz() ? 0 : config.getCpuHz();
                memTotal += null == config.getMemoryCapacity() ? 0 : config.getMemoryCapacity();
                // diskTotal += config.getDiskCapacity();
                cpuCore += null == config.getCpuCore() ? 0 : config.getCpuCore();
            }
            vms = cloudServerRepository.listByHid(host.getId());
            for (CloudServer vm : vms) {
                // diskUsed += null == vm.getDisk() ? 0 : vm.getDisk();
                if (null != vm.getTemplate() && vm.getIsTemplate()) {
                    continue;
                }
                if (config != null) {
                    vmCpuNum = null == vm.getCpu() ? 0 : vm.getCpu();
                    serverCpuNum = null == config.getCpuCore() ? 0 : config.getCpuCore();
                    Long cpuHz = null == config.getCpuHz() ? 0L : config.getCpuHz();
                    vmCpu = (int) ((double) vmCpuNum / serverCpuNum * cpuHz);
                    cpuUsed += vmCpu;
                }
                memUsed += null == vm.getMemory() ? 0 : vm.getMemory().doubleValue();
            }
        }
        diskTotal = model.getDiskTotal();
        diskUsed = model.getDiskUsed();
        cluster.setHostNum(hosts.size());
        cluster.setVmNum(vmNum - templateNum);
        cluster.setTemplateNum(templateNum);
        cluster.setCpuCore(cpuCore);
        cluster.setCpuTotal(cpuTotal);
        cluster.setMemTotal(BigDecimal.valueOf(memTotal).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
        cluster.setDiskTotal(BigDecimal.valueOf(diskTotal).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
        cluster.setCpuUsed(cpuUsed);
        cluster.setMemUsed(BigDecimal.valueOf(memUsed).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
        // 除了h3c 其他类型需要计算
        if (!CloudProvider.H3C.name().equals(cluster.getType())) {
            cluster.setDiskUsed(BigDecimal.valueOf(diskUsed).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
        }
        cluster.setCpuUnused(cpuTotal - cpuUsed);
        cluster.setMemUnused(
                BigDecimal.valueOf(memTotal - memUsed).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
        cluster.setDiskUnused(
                BigDecimal.valueOf(diskTotal - diskUsed).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
    }

    @Override
    public BocloudResult moveHost(JSONObject object, RequestContext context) {
        if (null == object) {
            return new BocloudResult<>(false, "参数格式错误");
        }
        String vendorType = object.getString("vendorType");
        if (CloudProvider.OPENSTACK.name().equalsIgnoreCase(vendorType)
                ||CloudProvider.EASYSTACK.name().equalsIgnoreCase(vendorType)
                || CloudProvider.POWERVC.name().equalsIgnoreCase(vendorType)) {
            String action = object.getString(Common.ACTION);
            if ("addOsHost".equalsIgnoreCase(action)) {
                return this.addHost(object.toJSONString(), context);
            } else if ("removeOsHost".equalsIgnoreCase(action)) {
                return this.removeHost(object.toJSONString(), context);
            }
        }
        ClusterOperateModel model = JSONObject.parseObject(object.toJSONString(), ClusterOperateModel.class);
        String path = Cluster.class.getSimpleName() + "_" + model.getClusterId();
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            Cluster cluster = this.clusterRepository.query(model.getClusterId());
            if (null == cluster) {
                return new BocloudResult<>(false, "集群不存在！");
            }
            Vdc vdc = vdcRepository.query(cluster.getVdcId());
            if (null == vdc) {
                return new BocloudResult<>(false, "虚拟数据中心不存在！");
            }
            CloudVendor vendor = cloudVendorRepository.query(model.getVendorId());
            if (null == vendor) {
                return new BocloudResult<>(false, "获取云供应商失败");
            }
            List<Long> hosts = model.getHosts();
            List<String> names = Lists.newArrayList();
            List<Server> servers = Lists.newArrayList();
            if (!ListTool.isEmpty(hosts)) {
                for (Long hostId : hosts) {
                    Server host = serverRepository.query(hostId);
                    // 宿主机在集群中并且没有进入维护模式的，不可移动
                    if (null != host.getClusterId() && !host.getMaintained() && host.getMaintained()) {
                        continue;
                    }
                    names.add(host.getName());
                    servers.add(host);
                }
            }
            HostOperateModel operateModel = new HostOperateModel();
            operateModel.setVdcName(model.getVdcName());
            operateModel.setClusterName(model.getClusterName());
            operateModel.setHosts(names);
            Long userId = context.getTarget();
            BocloudResult result = hostDriver.moveTo(vendor.getUuid(), null, operateModel);
            Map<Long, Long> clusterIdMap = new HashMap<>();
            if (result.isSuccess()) {
                if (StringUtils.isEmpty(model.getClusterName())) {// 移出集群
                    for (Server host : servers) {
                        clusterIdMap.put(host.getClusterId(), host.getClusterId());
                        host.setMenderId(userId);
                        host.setClusterId(null);
                        this.serverRepository.update(host);
                        ClusterNode node = this.clusterNodeRepository.queryByRid(host.getResourceId());
                        if (null != node) {
                            this.clusterNodeRepository.removeByRid(node.getResourceId(), userId);
                        }
                    }
                } else {// 移入集群
                    for (Server host : servers) {
                        if (null == host.getClusterId()) {
                            clusterIdMap.put(model.getClusterId(), model.getClusterId());
                            ClusterNode node = new ClusterNode(host.getManageIp(), host.getResourceId(), "PM",
                                    model.getClusterId());
                            node.setName(host.getName());
                            node.setCreatorId(userId);
                            node.setMenderId(userId);
                            node.setStatus(host.getStatus());
                            clusterNodeRepository.save(node);
                        } else {
                            clusterIdMap.put(host.getClusterId(), host.getClusterId());
                            ClusterNode node = this.clusterNodeRepository.queryByRid(host.getResourceId());
                            node.setClusterId(model.getClusterId());
                            node.setStatus(host.getStatus());
                            node.setMenderId(userId);
                            clusterNodeRepository.update(node);
                        }
                        host.setMenderId(userId);
                        host.setClusterId(model.getClusterId());
                        this.serverRepository.update(host);
                    }
                }
                // 同步到cmdb
                List<CmdbInfo> infos = Lists.newArrayList();
                for (Server host : servers) {
                    ServerConfig config = serverConfigRepository.getBySid(host.getId());
                    // 宿主机与对象的关系
                    List<CmdbRelation> relations = Lists.newArrayList();
                    relations.add(new CmdbRelation(ModuleCode.VDC.name(), 3L, ListUtils.getList(vdc.getGuid())));
                    if (StringUtils.isEmpty(model.getClusterName())) {
                        relations.add(new CmdbRelation(ModuleCode.VDC.name(), 1L, ListUtils.getList(vdc.getGuid())));
                    } else {
                        relations.add(
                                new CmdbRelation(ModuleCode.CLUSTER.name(), 1L, ListUtils.getList(cluster.getGuid())));
                    }
                    infos.add(CmdbInfoConvertor.getInfo(host, config, null, relations));
                }
                List<Server> list = serverRepository.listByCluster(cluster.getId());
                Long cpuTotal = 0L;
                Double memTotal = 0D;
                Double diskTotal = 0D;
                for (Server server : list) {
                    ServerConfig config = serverConfigRepository.getBySid(server.getId());
                    cpuTotal += config.getCpuHz();
                    memTotal += config.getMemoryCapacity();
                    diskTotal += config.getDiskCapacity();
                }
                cluster.setCpuTotal(cpuTotal);
                cluster.setMemTotal(memTotal);
                cluster.setDiskTotal(diskTotal);
                infos.add(CmdbInfoConvertor.getInfo(cluster, "modify", null));
                cmdbMessagePublisher.send(CmdbInfoConvertor.getModel(BoCloudService.IMS, infos));
                // 同步资源池数据
                List<VmResourcePool> pools = resourcePoolRepository.listByVdc(vdc.getId());
                BocloudResult bocloudResult = resourcePoolDriver.list(vendor.getUuid(), vdc.getName());
                if (bocloudResult.isSuccess()) {
                    List<VmResourcePool> newPools = JSONArray.parseArray(JSONObject.toJSONString(bocloudResult.getData()),
                            VmResourcePool.class);
                    vmwareTransporter.syncResourcePool(pools, newPools, vdc.getId(), vendor.getId(), userId);
                }
            }
            // 同步集群数据
            if (!clusterIdMap.isEmpty()) {
                for (Long clusterId : clusterIdMap.keySet()) {
                    Cluster newCluster = clusterRepository.query(clusterId);
                    if (null == newCluster) {
                        continue;
                    }
                    BocloudResult bocloudResult = clusterDriver.detailCluster(vendor.getUuid(),
                            newCluster.getClusterVal());
                    if (bocloudResult.isSuccess()) {
                        ClusterModel clusterModel = JSONObject
                                .parseObject(JSONObject.toJSONString(bocloudResult.getData()), ClusterModel.class);
                        if (null != clusterModel) {
                            newCluster.setMenderId(context.getTarget());
                            newCluster.setGmtModify(new Date());
                            newCluster.setCpuTotal(clusterModel.getCpuTotal());
                            newCluster.setMemTotal(clusterModel.getMemTotal());
                            newCluster.setDiskTotal(clusterModel.getDiskTotal());
                            newCluster.setCpuUsed(clusterModel.getCpuUsed());
                            newCluster.setMemUsed(clusterModel.getMemUsed());
                            newCluster.setDiskUsed(clusterModel.getDiskUsed());
                            newCluster.setHostNum(clusterModel.getHostNum());
                            newCluster.setVmNum(clusterModel.getVmNum());
                            newCluster.setTemplateNum(clusterModel.getTemplateNum());
                            newCluster.setCpuCore(clusterModel.getCpuCore());
                            clusterRepository.update(newCluster);
                        }
                    }
                }
            }
            return result;
        } catch (Exception e) {
            logger.error("add host exception", e);
            return new BocloudResult<>(false, "移动失败");
        }
    }

    /**
     * @since 2018-04-25 modify by sxp 增加磁盘告警阈值的设置
     */
    @Override
    public BocloudResult<AlarmThreshold> createAlarm(AlarmThreshold alarmThreshold) {
        String path = Cluster.class.getSimpleName() + "_" + alarmThreshold.getTarget();
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            Long target = alarmThreshold.getTarget();
            if (target == null) {
                return new BocloudResult<>(false, "集群告警阈值设置失败，需要传入集群的唯一标识(id)。");
            }
            AlarmThreshold oldThreshold = alarmThresholdRepository.getByTarget(target,
                    AlarmTargetCatalog.CLUSTER.name());
            if (null == oldThreshold) {
                alarmThreshold.setCatalog(AlarmTargetCatalog.CLUSTER.name());
                alarmThresholdRepository.save(alarmThreshold);
                return new BocloudResult<>(true, "集群告警阈值设置成功");
            } else {
                oldThreshold.setCpuYellowVal(alarmThreshold.getCpuYellowVal());
                oldThreshold.setCpuRedVal(alarmThreshold.getCpuRedVal());
                oldThreshold.setMemoryYellowVal(alarmThreshold.getMemoryYellowVal());
                oldThreshold.setMemoryRedVal(alarmThreshold.getMemoryRedVal());
                oldThreshold.setDiskYellowVal(alarmThreshold.getDiskYellowVal());
                oldThreshold.setDiskRedVal(alarmThreshold.getDiskRedVal());
                boolean flag = alarmThresholdRepository.update(oldThreshold);
                if (!flag) {
                    return new BocloudResult<>(false, "集群告警阈值更新失败");
                }
                return new BocloudResult<>(true, "集群告警阈值更新成功");
            }
        } catch (Exception e) {
            logger.error("Cluster Alarm threshold setting failed");
            return new BocloudResult<>(false, "集群告警阈值设置失败");
        }
    }

    @Override
    public BocloudResult<AlarmThreshold> getAlarm(Long target) {
        try {
            AlarmThreshold alarmThreshold = alarmThresholdRepository.getByTarget(target,
                    AlarmTargetCatalog.CLUSTER.name());
            if (null == alarmThreshold) {
                alarmThreshold = new AlarmThreshold();
            }
            return new BocloudResult<>(true, alarmThreshold, "查询成功");
        } catch (Exception e) {
            logger.error("Get error message：", e);
            return new BocloudResult<>(false, "查询失败");
        }
    }

    @Override
    public BocloudResult addHost(String params, RequestContext context) {
        JSONObject object = JSONObject.parseObject(params);
        if (null == object) {
            return new BocloudResult<>(false, "参数格式错误");
        }
        Long id = object.getLong("id");
        List<Long> serverIds = JSONArray.parseArray(object.getString("serverIds"), Long.class);
        String path = Cluster.class.getSimpleName() + "_" + id;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            Cluster cluster = this.clusterRepository.query(id);
            if (null == cluster) {
                logger.warn("Cluster does not exist!");
                return new BocloudResult<>(false, "数据不存在");
            }
            CloudVendor vendor = cloudVendorRepository.query(cluster.getVendorId());
            if (null == vendor) {
                logger.warn("Cloud vendor does not exist!");
                return new BocloudResult<>(false, "云平台不存在");
            }
            if (ListTool.isEmpty(serverIds)) {
                return new BocloudResult<>(false, "没有需要添加的主机");
            }
            // 电科云 主机组 加入 计算主机 计算主机 计算主机 2019年11月14日19:55:03
            if (CloudProvider.OPENSTACK.name().equals(vendor.getType())||CloudProvider.EASYSTACK.name().equals(vendor.getType())) {
                return addHost(cluster, vendor, serverIds, context);
            }
            List<Server> servers = Lists.newArrayList();
            for (Long serverId : serverIds) {
                Server server = serverRepository.query(serverId);
                if (null == server) {
                    return new BocloudResult<>(false, "选中的宿主机中存成已删除的宿主机，添加主机失败");
                }
                if (CloudProvider.POWERVC.name().equals(vendor.getType())) {
                    // 如果是powervc平台，需要检查该主机是否在默认主机组
                    Cluster clusterOfServer = clusterRepository.query(server.getClusterId());
                    if (!clusterOfServer.getUuid().equals(PowervcConstant.DEFAULT_OS_AGGREGATE_ID)) {
                        return new BocloudResult<>(false, "该主机已被添加到其他主机组");
                    }
                }
                servers.add(server);
            }
            List<BocloudResult> succList = Lists.newArrayList();
            List<BocloudResult> failList = Lists.newArrayList();
            for (Server server : servers) {
                BocloudResult result;
                if (CloudProvider.POWERVC.name().equals(vendor.getType())) {
                    result = hostAggregateDriver.addHost(cluster.getUuid(), server.getHostname(), vendor.getUuid(),
                            null);
                } else {
                    result = hostAggregateDriver.addHost(cluster.getUuid(), server.getName(), vendor.getUuid(), null);
                }
                if (result.isSuccess()) {
                    server.setGmtModify(new Date());
                    server.setMenderId(context.getTarget());
                    server.setClusterId(id);
                    serverRepository.update(server);
                    succList.add(result);
                    // 宿主机加入集群后 删除宿主机和资源池的关联关系
                    poolGroupRelationRepository.removeByTarget(server.getId(), "Host");
                } else {
                    failList.add(result);
                }
            }
            int success = succList.size();
            int fail = failList.size();
            if (fail == servers.size()) {
                return new BocloudResult<>(false, "主机添加失败");
            } else if (success == servers.size()) {
                return new BocloudResult<>(true, "主机添加成功");
            } else {
                return new BocloudResult<>(true, "主机添加成功【" + success + "】个,失败【" + fail + "】");
            }
        } catch (Exception e) {
            logger.error("Get error message:", e);
            return new BocloudResult<>(false, "主机添加失败");
        }
    }

    private BocloudResult addHost(Cluster cluster, CloudVendor vendor, List<Long> serverIds, RequestContext context) {
        try {
            List<ClusterNode> clusterNodes = Lists.newArrayList();
            for (Long serverId : serverIds) {
                ClusterNode clusterNode = clusterNodeRepository.query(serverId);
                if (null == clusterNode) {
                    return new BocloudResult<>(false, "选中的主机中存成已删除的宿主机，添加主机失败");
                }
                clusterNodes.add(clusterNode);
            }
            List<BocloudResult> succList = Lists.newArrayList();
            List<BocloudResult> failList = Lists.newArrayList();
            for (ClusterNode node : clusterNodes) {
                BocloudResult result = hostAggregateDriver.addHost(cluster.getUuid(), node.getName(), vendor.getUuid(),
                        null);
                if (result.isSuccess()) {
                    node.setGmtModify(new Date());
                    node.setMenderId(context.getTarget());
                    node.setClusterId(cluster.getId());
                    clusterNodeRepository.update(node);
                    Server server = serverRepository.getByHostName(node.getName(), vendor.getId());
                    if (null != server) {
                        server.setClusterId(cluster.getId());
                        serverRepository.update(server);
                    }
                    succList.add(result);
                } else {
                    failList.add(result);
                }
            }
            int success = succList.size();
            int fail = failList.size();
            if (fail == clusterNodes.size()) {
                return new BocloudResult<>(false, "主机添加失败");
            } else if (success == clusterNodes.size()) {
                return new BocloudResult<>(true, "主机添加成功");
            } else {
                return new BocloudResult<>(true, "主机添加成功【" + success + "】个,失败【" + fail + "】");
            }
        } catch (Exception e) {
            logger.error("主机添加失败：" + e.getMessage());
            return new BocloudResult<>(false, "主机添加失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult removeHost(String params, RequestContext context) {
        JSONObject object = JSONObject.parseObject(params);
        if (null == object) {
            return new BocloudResult<>(false, "参数格式错误");
        }
        Long id = object.getLong("clusterId");
        List<Long> serverIds = JSONArray.parseArray(object.getString("serverIds"), Long.class);
        String path = Cluster.class.getSimpleName() + "_" + id;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            Cluster cluster = this.clusterRepository.query(id);
            if (null == cluster) {
                logger.warn("Cluster does not exist!");
                return new BocloudResult<>(false, "数据不存在");
            }
            CloudVendor vendor = cloudVendorRepository.query(cluster.getVendorId());
            if (null == vendor) {
                logger.warn("Cloud vendor does not exist!");
                return new BocloudResult<>(false, "云平台不存在");
            }
            if (ListTool.isEmpty(serverIds)) {
                return new BocloudResult<>(false, "没有需要添加的主机");
            }
            // 电科云 主机组 加入 计算主机 计算主机 计算主机 2019年11月14日19:55:03
            if (CloudProvider.OPENSTACK.name().equals(vendor.getType())||CloudProvider.EASYSTACK.name().equals(vendor.getType())) {
                return removeHost(cluster, vendor, serverIds, context);
            }
            List<Server> servers = Lists.newArrayList();
            for (Long serverId : serverIds) {
                Server server = serverRepository.query(serverId);
                if (null == server) {
                    return new BocloudResult<>(false, "选中的宿主机中存成已删除的宿主机，移出主机失败");
                }
                servers.add(server);
            }
            List<BocloudResult> succList = Lists.newArrayList();
            List<BocloudResult> failList = Lists.newArrayList();
            for (Server server : servers) {
                BocloudResult result;
                if (CloudProvider.POWERVC.name().equals(vendor.getType())) {
                    result = hostAggregateDriver.removeHost(cluster.getUuid(), server.getHostname(), vendor.getUuid(),
                            null);
                } else {
                    result = hostAggregateDriver.removeHost(cluster.getUuid(), server.getName(), vendor.getUuid(),
                            null);
                }
                if (result.isSuccess()) {
                    server.setGmtModify(new Date());
                    server.setMenderId(context.getTarget());
                    if (CloudProvider.POWERVC.name().equals(vendor.getType())) {
                        Cluster clusterDefault = clusterRepository.queryByUuid(PowervcConstant.DEFAULT_OS_AGGREGATE_ID,
                                vendor.getId());
                        server.setClusterId(clusterDefault == null ? null : clusterDefault.getId());
                    } else {
                        server.setClusterId(null);
                    }
                    serverRepository.update(server);
                    // 同步资源池关系
                    syncPoolGroupRelation(cluster.getId(), server.getId());
                    succList.add(result);
                } else {
                    failList.add(result);
                }
            }
            int success = succList.size();
            int fail = failList.size();
            if (fail == servers.size()) {
                return new BocloudResult<>(false, "主机移出失败");
            } else if (success == servers.size()) {
                return new BocloudResult<>(true, "主机移出成功");
            } else {
                return new BocloudResult<>(true, "主机移出成功【" + success + "】个,失败【" + fail + "】");
            }
        } catch (Exception e) {
            logger.error("Get error message:", e);
            return new BocloudResult<>(false, "主机移除失败");
        }
    }

    private BocloudResult removeHost(Cluster cluster, CloudVendor vendor, List<Long> serverIds,
                                     RequestContext context) {
        try {
            List<ClusterNode> clusterNodes = Lists.newArrayList();
            for (Long serverId : serverIds) {
                ClusterNode clusterNode = clusterNodeRepository.query(serverId);
                if (null == clusterNode) {
                    return new BocloudResult<>(false, "选中的主机中存成已删除的宿主机，添加主机失败");
                }
                clusterNodes.add(clusterNode);
            }
            List<BocloudResult> succList = Lists.newArrayList();
            List<BocloudResult> failList = Lists.newArrayList();
            for (ClusterNode node : clusterNodes) {
                BocloudResult result = hostAggregateDriver.removeHost(cluster.getUuid(), node.getName(),
                        vendor.getUuid(), null);
                if (result.isSuccess()) {
                    node.setGmtModify(new Date());
                    node.setMenderId(context.getTarget());
                    node.setClusterId(null);
                    clusterNodeRepository.update(node);
                    succList.add(result);
                } else {
                    failList.add(result);
                }
            }
            int success = succList.size();
            int fail = failList.size();
            if (fail == clusterNodes.size()) {
                return new BocloudResult<>(false, "主机移除失败");
            } else if (success == clusterNodes.size()) {
                return new BocloudResult<>(true, "主机移除成功");
            } else {
                return new BocloudResult<>(true, "主机移除成功【" + success + "】个,失败【" + fail + "】");
            }
        } catch (Exception e) {
            logger.error("主机移除失败：" + e.getMessage());
            return new BocloudResult<>(false, "主机移除失败：" + e.getMessage());
        }
    }

    /**
     * 宿主机B属于集群A，集群A关联了资源池A，将宿主机B移除集群A变为游离节点，资源池A中包含集群A+宿主机B
     *
     * @param clusterId
     * @param hostId
     */
    private void syncPoolGroupRelation(Long clusterId, Long hostId) {
        try {
            // 查询当前集群是否绑定资源池
            List<PoolGroupRelation> poolGroupList = poolGroupRelationRepository.listByTarget(clusterId, "Cluster");
            if (null != poolGroupList && poolGroupList.size() > 0) {
                for (PoolGroupRelation poolGroupRelation : poolGroupList) {
                    Long poolGroupId = poolGroupRelation.getPoolGroupId();
                    // 将宿主机 与 资源池绑定
                    PoolGroupRelation relation = new PoolGroupRelation();
                    relation.setPoolGroupId(poolGroupId);
                    relation.setCategory("Host");
                    relation.setTarget(hostId);
                    poolGroupRelationRepository.save(relation);
                }
            }
        } catch (Exception e) {
            logger.error("sync poolgrouprelation error :", e);
        }
    }

    @Override
    public BocloudResult performance(String params) {
        try {
        	JSONObject object = JSONTools.isJSONObj(params);
            CloudVendor vendor = this.cloudVendorRepository.query(object.getLong("vendorId"));
            if (null == vendor) {
                logger.warn("CloudVendor does not exist!");
                return new BocloudResult<>(false, "供应商不存在");
            }
            List<String> types = Lists.newArrayList();
            types.add("CPU");
            types.add("MEM");
            return new VmwareMonitorUtils(monitorDriver).getPerformance(object, vendor.getUuid(), types,
                    "ClusterComputeResource");
        } catch (Exception e) {
            logger.error("查询数据失败", e);
            return new BocloudResult<>(false, "查询失败");
        }
    }

    @Override
    public BocloudResult<Map<String, Object>> getTrend(Long id, String params) {
        JSONObject object = JSONTools.isJSONObj(params);
        if (null == object) {
            logger.error("Parameter {} format error", params);
            return new BocloudResult<>(false, "参数格式错误");
        }
        // 统计的资源分类
        String categorys = object.getString("categorys");
        if (StringUtils.isEmpty(categorys)) {
            logger.error("Parameter {} format error", params);
            return new BocloudResult<>(false, "参数格式不正确");
        }
        List<ChartParam> categoryList = JSONArray.parseArray(categorys, ChartParam.class);
        Map<String, Object> resultMap = Maps.newHashMap();
        try {
            Date now = new Date();
            Map<String, List<ClusterUsage>> map = Maps.newHashMap();
            for (ChartParam chartParam : categoryList) {
                Date pre = null;
                switch (Measure.valueOf(chartParam.getMeasure())) {
                    case week:
                        pre = DateUtils.addDay(now, -7);
                        break;
                    case month:
                        pre = DateUtils.addMonth(now, -1);
                        break;
                    case quarter:
                        pre = DateUtils.addMonth(now, -3);
                        break;
                    case half:
                        pre = DateUtils.addMonth(now, -6);
                        break;
                    case year:
                        pre = DateUtils.addMonth(now, -12);
                        break;
                    default:
                        logger.error("Parameter {} format error", params);
                        return new BocloudResult<>(false, "参数格式不正确");
                }
                List<ClusterUsage> usages = null;
                if (map.containsKey(chartParam.getMeasure())) {
                    usages = map.get(chartParam.getMeasure());
                } else {
                    List<Param> paramLists = Lists.newArrayList();
                    paramLists.add(new Param(MapTools.simpleMap("clusterId", id), Sign.EQ));
                    paramLists.add(new Param(
                            MapTools.simpleMap("date", DateUtils.dateToString(now, "yyyy-MM-dd") + " 00:00:00"),
                            Sign.LET));
                    paramLists.add(new Param(
                            MapTools.simpleMap("date", DateUtils.dateToString(pre, "yyyy-MM-dd") + " 00:00:00"),
                            Sign.GET));
                    Map<String, String> sorter = Maps.newHashMap();
                    sorter.put("date", Common.ZERO);
                    usages = clusterUsageRepository.list(paramLists, sorter);
                    map.put(chartParam.getMeasure(), usages);
                }
                List<String> keys = Lists.newArrayList();
                List<Object> datas = Lists.newArrayList();
                for (ClusterUsage usage : usages) {
                    keys.add(DateUtils.dateToString(usage.getDate(), "yyyy-MM-dd"));
                    if ("CPU".equalsIgnoreCase(chartParam.getCategory())) {
                        datas.add(usage.getCpu());
                    } else if ("MEM".equalsIgnoreCase(chartParam.getCategory())) {
                        datas.add(usage.getMem());
                    } else if ("DISK".equalsIgnoreCase(chartParam.getCategory())) {
                        datas.add(usage.getDisk());
                    } else if ("INST".equalsIgnoreCase(chartParam.getCategory())) {
                        datas.add(usage.getInstance());
                    }
                }
                JSONObject value = new JSONObject();
                value.put("name", "使用量");
                value.put("data", datas);
                List<JSONObject> values = Lists.newArrayList();
                values.add(value);
                JSONObject trend = new JSONObject();
                trend.put("keys", keys);
                trend.put("values", values);
                resultMap.put(chartParam.getCategory(), trend);
            }
            return new BocloudResult<>(true, resultMap, "查询成功");
        } catch (Exception e) {
            logger.error("Get cluster usage info error:", e);
            return new BocloudResult<>(false, "查询失败");
        }
    }

    @Override
	public BocloudResult batchRemove(List<Long> idArray, RequestContext context) {
		if (ListTool.isEmpty(idArray)) {
			return new BocloudResult<>(false, "没有需要删除的数据！");
		}
		try {
			List<BocloudResult> succList = Lists.newArrayList();
			List<BocloudResult> failList = Lists.newArrayList();
			Long vendorId = null;
			for (Long id : idArray) {
				Cluster cluster = clusterRepository.query(id);
				if (null != cluster) {
					if (null == vendorId) {
						vendorId = cluster.getVendorId();
					}
					BocloudResult result = remove(id, context);
					if (result.isSuccess()) {
						succList.add(new BocloudResult<>(true, "【" + cluster.getName() + "】删除成功"));
					} else {
						failList.add(
								new BocloudResult<>(false, "【" + cluster.getName() + "】删除失败：" + result.getMessage()));
					}
				}
			}
			CloudVendor vendor = cloudVendorRepository.query(vendorId);
			String operate = vendor.getType().toLowerCase() + ".cluster";
			// 删除成功的数量
			int success = succList.size();
			// 删除失败的数量
			int fail = failList.size();
			String content = null;
			if (fail == idArray.size()) {
				content = "批量删除失败，详情如下：\n";
				for (BocloudResult bocloudResult : failList) {
					content += bocloudResult.getMessage() + "\n";
				}
				resourceEventPublisher
						.send(new OperateResult(false, content, operate, MapTools.simpleMap("vendorId", vendor.getId()),
								OperateResult.OperateCategory.ResourceEvent, context));
			} else {
				content = "批量删除成功【" + success + "】个,失败【" + fail + "】个，详情如下：\n";
				for (BocloudResult bocloudResult : succList) {
					content += bocloudResult.getMessage() + "\n";
				}
				for (BocloudResult bocloudResult : failList) {
					content += bocloudResult.getMessage() + "\n";
				}
				resourceEventPublisher
						.send(new OperateResult(true, content, operate, MapTools.simpleMap("vendorId", vendor.getId()),
								OperateResult.OperateCategory.ResourceEvent, context));
			}
		} catch (Exception e) {
			logger.error("batch remove volume fail:", e);
			return new BocloudResult<>(false, "批量删除任务下发失败");
		}
		return new BocloudResult<>(true, "批量删除任务已下发，正在执行...");
	}

    @Override
    public BocloudResult syncHostByCluster(Long id, RequestContext context) {
        try {
            Cluster cluster = clusterRepository.query(id);
            if (null == cluster) {
                logger.error("主机集群不存在!");
                return new BocloudResult(false, "主机集群不存在");
            }
            Vdc vdc = vdcRepository.query(cluster.getVdcId());
            if (null == vdc) {
                logger.error("数据中心不存在!");
                return new BocloudResult(false, "数据中心不存在");
            }
            CloudVendor vendor = cloudVendorRepository.query(cluster.getVendorId());
            if (null == vendor) {
                logger.error("平台不存在!");
                return new BocloudResult(false, "平台不存在");
            }
            // 启动一个线程
            new Thread(() -> {
                Date startTime = new Date();
                String path = CloudVendor.class.getSimpleName() + "_" + vendor.getId();
                String operate = vendor.getType().toLowerCase() + ".sync";
                BocloudResult result = new BocloudResult(false, "暂不支持");
                OperateResult operateResult = new OperateResult(true, "集群下宿主机同步成功", operate,
                        MapTools.simpleMap("vendorId", vendor.getId()), OperateResult.OperateCategory.ResourceEvent, context);
                try (BocloudACLock lock = lockFactory.getACLock(path)) {
                    Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
                    CloudVendor cloudVendor = cloudVendorRepository.query(vendor.getId());
                    if (null == cloudVendor) {
                        logger.error("平台数据不存在!");
                        result = new BocloudResult(false, "平台数据不存在!");
                        operateResult.setSuccess(false);
                        operateResult.setMessage("平台数据不存在！");
                    }
                    if (operateResult.isSuccess()) {
                        String vendorUuid = vendor.getUuid();
                        String vendorName = vendor.getName();
                        String clusterName = cluster.getName();
                        logger.info("开始执行平台{} 主机集群{} 的宿主机同步操作", vendorName, clusterName);
                        result = hostDriver.listByCluster(vendorUuid, clusterName);
                        if (result.isSuccess()) {
                            SingleVmwareTransportor tool = new SingleVmwareTransportor(
                                    clusterRepository, clusterNodeRepository,
                                    networkRepository, networkCardRepository,
                                    switcherRepository, portGroupRepository, ipPoolPortGroupRepository,
                                    dataStoreRepository, storeHostRepository, networkHostRepository,
                                    serverRepository, serverConfigRepository, serverAssetsRepository,
                                    scsiLunRepository, profileRepository,
                                    resourceRepository, ipRepository, ipPoolRepository,
                                    amqpTemplate);
                            result = tool.syncHostByCluster(vendor, vdc, cluster, result.getData(), context.getTarget());
                        }
                    }
                    logger.info("集群下宿主机同步任务结果：{}", result.getMessage());
                    operateResult.setSuccess(result.isSuccess());
                    operateResult.setMessage(result.getMessage());
                } catch (Exception e) {
                    logger.error("集群下宿主机同步任务异常", e);
                    operateResult.setSuccess(false);
                    operateResult.setMessage("集群下宿主机同步任务异常");
                }
                resourceEventPublisher.send(operateResult);
                VendorSyncRecord record = new VendorSyncRecord();
                record.setVendorId(vendor.getId());
                record.setStartTime(startTime);
                record.setEndTime(new Date());
                record.setCost(record.getEndTime().getTime() - startTime.getTime());
                record.setResult(operateResult.getMessage());
                record.setCreatorId(context.getTarget());
                record.setSyncResult(operateResult.isSuccess());
                record.setAuto(false);
                amqpTemplate.convertAndSend("vendor.record.queue", record);
                if (operateResult.isSuccess()) {
                    // 发送给云平台统计队列对云平台重新统计
                    JSONObject object = new JSONObject();
                    object.put(Common.VENDORID, vendor.getId());
                    amqpTemplate.convertAndSend("vendor.statistics.queue", object);
                }
                // 更新云平台最后一次同步时间
                vendor.setGmtModify(record.getEndTime());
                vendor.setMenderId(context.getTarget());
                cloudVendorRepository.update(vendor);
            }).start();
            return new BocloudResult(true, "同步任务已经下发，正在执行……");
        } catch (Exception e) {
            logger.error("sync host by cluster exception ", e);
            return new BocloudResult(false, "同步失败!");
        }
    }
}
