package com.bocloud.ims.service.transportor;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.entity.enums.*;
import com.bocloud.cmp.model.HostSystem;
import com.bocloud.cmp.model.ScsiLunModel;
import com.bocloud.common.enums.BoCloudService;
import com.bocloud.common.enums.OSCategory;
import com.bocloud.common.enums.ResourceCatalog;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.utils.IDFactory;
import com.bocloud.common.utils.ListTool;
import com.bocloud.ims.entity.resource.*;
import com.bocloud.ims.interfaces.resource.IpService;
import com.bocloud.ims.interfaces.scheduler.SnapshotTaskService;
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.CmdbModel;
import com.bocloud.ims.service.model.cmdb.CmdbRelation;
import com.bocloud.ims.service.utils.CmdbInfoConvertor;
import com.bocloud.ims.service.utils.IPAddress;
import com.bocloud.ims.service.utils.ListUtils;
import com.bocloud.ims.service.utils.SingleSyncVmwareUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.Map.Entry;

/**
 * 同步VMware工具类
 *
 * @author weiwei
 */
public class SingleVmwareTransportor {
    private static Logger logger = LoggerFactory.getLogger(SingleVmwareTransportor.class);
    private VdcRepository vdcRepository;
    private CloudServerRepository cloudServerRepository;
    private DataStoreRepository dataStoreRepository;
    private SnapshotRepository snapshotRepository;
    private NetworkRepository networkRepository;
    private ClusterRepository clusterRepository;
    private StoreHostRepository storeHostRepository;
    private ServerRepository serverRepository;
    private NetworkCardRepository networkCardRepository;
    private PortGroupRepository portGroupRepository;
    private NetworkHostRepository networkHostRepository;
    private SingleSyncVmwareUtils utils;
    private ClusterNodeRepository clusterNodeRepository;
    private ServerConfigRepository serverConfigRepository;
    private ServerAssetsRepository serverAssetsRepository;
    private ResourceRepository resourceRepository;
    private IpRepository ipRepository;
    private IpPoolRepository ipPoolRepository;
    private SwitcherRepository switcherRepository;
    private ImageRepository imageRepository;
    private ResourcePoolRepository resourcePoolRepository;
    private ServerLabelRepository serverLabelRepository;
    private SnapshotTaskService snapshotTaskService;
    private AmqpTemplate amqpTemplate;
    private IpService ipService;
    private PbmProfileRepository profileRepository;
    private ScsiLunRepository scsiLunRepository;
    private IpPoolPortGroupRepository ipPoolPortGroupRepository;
    private TagRepository tagRepository;

    public SingleVmwareTransportor() {
        super();
    }

    public SingleVmwareTransportor(VdcRepository vdcRepository, ClusterRepository clusterRepository, DataStoreRepository dataStoreRepository,
                                   NetworkRepository networkRepository, NetworkCardRepository networkCardRepository,
                                   SwitcherRepository switcherRepository, PortGroupRepository portGroupRepository, IpPoolPortGroupRepository ipPoolPortGroupRepository,
                                   AmqpTemplate amqpTemplate) {
        super();
        this.vdcRepository = vdcRepository;
        this.clusterRepository = clusterRepository;
        this.dataStoreRepository = dataStoreRepository;
        this.networkRepository = networkRepository;
        this.networkCardRepository = networkCardRepository;
        this.switcherRepository = switcherRepository;
        this.portGroupRepository = portGroupRepository;
        this.ipPoolPortGroupRepository = ipPoolPortGroupRepository;
        this.amqpTemplate = amqpTemplate;
        utils = new SingleSyncVmwareUtils(clusterRepository);
    }

    public SingleVmwareTransportor(ClusterRepository clusterRepository, ClusterNodeRepository clusterNodeRepository,
                                   NetworkRepository networkRepository, NetworkCardRepository networkCardRepository,
                                   SwitcherRepository switcherRepository, PortGroupRepository portGroupRepository, IpPoolPortGroupRepository ipPoolPortGroupRepository,
                                   DataStoreRepository dataStoreRepository,
                                   StoreHostRepository storeHostRepository, NetworkHostRepository networkHostRepository,
                                   ServerRepository serverRepository, ServerConfigRepository serverConfigRepository, ServerAssetsRepository serverAssetsRepository,
                                   ScsiLunRepository scsiLunRepository, PbmProfileRepository profileRepository,
                                   ResourceRepository resourceRepository, IpRepository ipRepository, IpPoolRepository ipPoolRepository,
                                   AmqpTemplate amqpTemplate) {
        super();
        this.clusterRepository = clusterRepository;
        this.clusterNodeRepository = clusterNodeRepository;
        this.networkRepository = networkRepository;
        this.networkCardRepository = networkCardRepository;
        this.switcherRepository = switcherRepository;
        this.portGroupRepository = portGroupRepository;
        this.ipPoolPortGroupRepository = ipPoolPortGroupRepository;
        this.dataStoreRepository = dataStoreRepository;
        this.storeHostRepository = storeHostRepository;
        this.networkHostRepository = networkHostRepository;
        this.serverRepository = serverRepository;
        this.serverConfigRepository = serverConfigRepository;
        this.serverAssetsRepository = serverAssetsRepository;
        this.scsiLunRepository = scsiLunRepository;
        this.profileRepository = profileRepository;
        this.resourceRepository = resourceRepository;
        this.ipRepository = ipRepository;
        this.amqpTemplate = amqpTemplate;
        this.ipPoolRepository = ipPoolRepository;
        utils = new SingleSyncVmwareUtils(serverRepository, serverConfigRepository,
                dataStoreRepository, storeHostRepository,
                networkRepository, networkHostRepository, networkCardRepository,
                resourceRepository, ipRepository);
    }

    public SingleVmwareTransportor(NetworkRepository networkRepository, NetworkCardRepository networkCardRepository,
                                   SwitcherRepository switcherRepository, PortGroupRepository portGroupRepository, IpPoolPortGroupRepository ipPoolPortGroupRepository,
                                   DataStoreRepository dataStoreRepository,
                                   StoreHostRepository storeHostRepository, NetworkHostRepository networkHostRepository,
                                   CloudServerRepository cloudServerRepository, ImageRepository imageRepository, SnapshotRepository snapshotRepository, VolumeRepository volumeRepository,
                                   ResourceRepository resourceRepository, IpRepository ipRepository, IpPoolRepository ipPoolRepository, SnapshotTaskService snapshotTaskService,
                                   TagRepository tagRepository, ServerLabelRepository serverLabelRepository, AmqpTemplate amqpTemplate) {
        super();
        this.networkRepository = networkRepository;
        this.networkCardRepository = networkCardRepository;
        this.switcherRepository = switcherRepository;
        this.portGroupRepository = portGroupRepository;
        this.ipPoolPortGroupRepository = ipPoolPortGroupRepository;
        this.dataStoreRepository = dataStoreRepository;
        this.storeHostRepository = storeHostRepository;
        this.networkHostRepository = networkHostRepository;
        this.cloudServerRepository = cloudServerRepository;
        this.imageRepository = imageRepository;
        this.snapshotRepository = snapshotRepository;
        this.resourceRepository = resourceRepository;
        this.ipRepository = ipRepository;
        this.ipPoolRepository = ipPoolRepository;
        this.snapshotTaskService = snapshotTaskService;
        this.tagRepository = this.tagRepository;
        this.serverLabelRepository = this.serverLabelRepository;
        this.amqpTemplate = amqpTemplate;
        utils = new SingleSyncVmwareUtils(cloudServerRepository, imageRepository, snapshotRepository, volumeRepository,
                dataStoreRepository, storeHostRepository, networkRepository, networkHostRepository, networkCardRepository,
                resourceRepository, ipRepository);
    }

    /***
     *
     * @param vendor
     * @param vdc
     * @param type
     * @param typeName
     * @param data
     * @param managerId
     * @return
     */
    public BocloudResult syncByVdc(CloudVendor vendor, Vdc vdc, String type, String typeName, Object data, Long managerId) {
        CmdbModel model = new CmdbModel();
        model.setUuid(IDFactory.instance().uuid());
        model.setServiceName(BoCloudService.IMS.name());
        model.setManagerId(managerId);
        List<CmdbInfo> infos = new ArrayList<>();
        // 添加云平台数据
        infos.add(CmdbInfoConvertor.getInfo(vendor, null, null, CloudProvider.VMWARE));
        try {
            if (null != data) {
                Long vendorId = vendor.getId();
                Long vdcId = vdc.getId();
                String vdcGuid = vdc.getGuid();
                // 获取同步数据
                String content = JSONObject.toJSONString(data);
                if ("cluster".equalsIgnoreCase(type)) {
                    List<Cluster> newClusters = JSONObject.parseArray(content, Cluster.class);
                    // 同步集群
                    List<Cluster> clusters = clusterRepository.listByVdc(vdcId, "COMPUTE");
                    logger.info("Start sync cluster of datacenter[" + vdcId + "]");
                    syncCluster(clusters, newClusters, vendorId, vdc.getId(), managerId, infos, vdcGuid);
                } else if ("network".equalsIgnoreCase(type)) {
                    Vdc vdcNetworks = JSONObject.parseObject(content, Vdc.class);
                    // 同步分布式交换机
                    List<Switcher> switchers = switcherRepository.listByVdc(vdcId, "DVSWITCH");
                    logger.info("Start sync dvswitcher of datacenter[" + vdcId + "]");
                    syncSwitcher(switchers, vdcNetworks.getSwitchers(), vendorId, vdcId, null, managerId, "DVSWITCH", infos,
                            vendor.getGuid());
                    // 获取分布式交换机
                    Map<String, Long> dvswitchMap = Maps.newHashMap();
                    Map<String, String> groupMap = Maps.newHashMap();
                    switchers = switcherRepository.listByVdc(vdcId, "DVSWITCH");
                    for (Switcher switcher : switchers) {
                        dvswitchMap.put(switcher.getSwitcherVal(), switcher.getId());
                        List<PortGroup> groups = portGroupRepository.listBySwitcher(switcher.getId());
                        for (PortGroup group : groups) {
                            groupMap.put(group.getGroupVal(), switcher.getSwitcherVal());
                        }
                    }
                    // 同步网络
                    List<Network> networks = networkRepository.listByVdc(vdcId);
                    Map<String, Network> networkMap = Maps.newHashMap();
                    logger.info("Start sync network of datacenter[" + vdcId + "]");
                    syncNetwork(networks, vdcNetworks.getNetworks(), vendorId, vdcId, managerId, networkMap, dvswitchMap, infos, vdcGuid);
                } else if ("datastore".equalsIgnoreCase(type)) {
                    List<DataStore> dataStoreList = JSONObject.parseArray(content, DataStore.class);
                    // 同步存储
                    Map<String, DataStore> storeMap = new HashMap<>();
                    List<DataStore> stores = dataStoreRepository.listByVdc(vdcId);
                    logger.info("Start sync data store of datacenter[" + vdcId + "]");
                    syncStore(storeMap, stores, dataStoreList, vendorId, vdcId, managerId, infos, vdcGuid);
                }
            }
            model.setData(infos);
            // 发送消息到cmdb模块，进行数据同步
            amqpTemplate.convertAndSend("cmdb.message.queue", JSONObject.parseObject(JSONObject.toJSONString(model)));
            return new BocloudResult(true, "云平台【 " + vendor.getName() + " 】数据中心【" + vdc.getName() + "】下" + typeName + "数据同步成功");
        } catch (Exception e) {
            logger.error("Sync vdc error:", e);
            return new BocloudResult(false, "云平台【 " + vendor.getName() + " 】数据中心【" + vdc.getName() + "】下" + typeName + "数据同步失败");
        }
    }

    /***
     *  同步集群
     * @param oldClusters
     * @param newClusters
     * @param vendorId
     * @param vdcId
     * @param managerId
     * @param infos
     * @param vdcGuid
     * @throws Exception
     */
    private void syncCluster(List<Cluster> oldClusters, List<Cluster> newClusters, Long vendorId, Long vdcId,
                             Long managerId, List<CmdbInfo> infos, String vdcGuid) throws Exception {
        if (!ListTool.isEmpty(oldClusters) && ListTool.isEmpty(newClusters)) {
            List<Cluster> clusters = clusterRepository.listByVendor(vendorId);
            for (Cluster cluster : clusters) {
                // cmdb：删除集群
                infos.add(CmdbInfoConvertor.getInfo(cluster, "delete", null, CloudProvider.VMWARE));
            }
            clusterRepository.removeByVdc(vdcId, managerId);
        } else {
            Map<String, Cluster> oldMap = Maps.newHashMap();
            for (Cluster cluster : oldClusters) {
                if (oldMap.containsKey(cluster.getClusterVal())) {
                    clusterRepository.remove(cluster.getId(), managerId);
                } else {
                    oldMap.put(cluster.getClusterVal(), cluster);
                }
            }
            for (Cluster cluster : newClusters) {
                List<CmdbRelation> relations = Lists.newArrayList();
                relations.add(new CmdbRelation(ModuleCode.VC_DC.name(), 1L, ListUtils.getList(vdcGuid)));
                if (oldMap.containsKey(cluster.getClusterVal())) {
                    Cluster oldCluster = oldMap.get(cluster.getClusterVal());
                    // 更新集群
                    utils.mergeCluster(oldCluster, cluster, managerId);
                    // 移除存在更新的集群
                    oldMap.remove(cluster.getClusterVal());
                    // CMDB更新集群数据
                    infos.add(CmdbInfoConvertor.getInfo(oldCluster, null, relations, CloudProvider.VMWARE));
                } else {
                    cluster.preSave(managerId, managerId, vendorId, vdcId);
                    cluster.setType(CloudProvider.VMWARE.name());
                    cluster.setUuid(IDFactory.instance().uuid());
                    cluster.setCpuDistributableRatio(BigDecimal.valueOf(100));
                    cluster.setMemDistributableRatio(BigDecimal.valueOf(100));
                    cluster.setCpuExcessRatio(4L);
                    cluster.setCategory("COMPUTE");
                    cluster.setStatus("RUNNING");
                    clusterRepository.save(cluster);
                    // CMDB添加集群数据
                    infos.add(CmdbInfoConvertor.getInfo(cluster, null, relations, CloudProvider.VMWARE));
                }
            }
            // 删除不存在的集群
            Iterator<Cluster> clusters = oldMap.values().iterator();
            while (clusters.hasNext()) {
                Cluster cluster = clusters.next();
                infos.add(CmdbInfoConvertor.getInfo(cluster, "delete", null, CloudProvider.VMWARE));
                clusterRepository.remove(cluster.getId(), managerId);
            }
        }
    }

    public void syncSwitcher(List<Switcher> oldSwitchers, List<Switcher> newSwitchers, Long vendorId, Long vdcId,
                             Long hostId, Long managerId, String type, List<CmdbInfo> infos, String vendorGuid) throws Exception {
        if (!ListTool.isEmpty(oldSwitchers) && ListTool.isEmpty(newSwitchers)) {
            for (Switcher switcher : oldSwitchers) {
                // cmdb删除虚拟机数据
                infos.add(CmdbInfoConvertor.getInfo(switcher, "delete", null, CloudProvider.VMWARE));
                networkCardRepository.release(switcher.getId(), managerId);
                portGroupRepository.removeBySwitcher(switcher.getId(), managerId);
            }
            if ("DVSWITCH".equals(type)) {
                switcherRepository.removeByVdc(vdcId, "DVSWITCH", managerId);
            } else {
                switcherRepository.removeByHostId(hostId, managerId);
            }
        } else {
            Map<String, Switcher> oldMap = Maps.newHashMap();
            for (Switcher switcher : oldSwitchers) {
                oldMap.put(switcher.getSwitcherVal(), switcher);
            }
            for (Switcher switcher : newSwitchers) {
                List<CmdbRelation> relations = Lists.newArrayList();
                relations.add(new CmdbRelation(ModuleCode.VC_VENDOR.name(), 2L, ListUtils.getList(vendorGuid)));
                String switcherGuid = null;
                Long switcherId = null;
                if (oldMap.containsKey(switcher.getSwitcherVal())) {
                    Switcher oldSwitcher = oldMap.get(switcher.getSwitcherVal());
                    switcher.setId(oldSwitcher.getId());
                    switcher.setGmtCreate(oldSwitcher.getGmtCreate());
                    switcher.setGmtModify(new Date());
                    switcher.setCreatorId(oldSwitcher.getCreatorId());
                    switcher.setMenderId(managerId);
                    switcher.setDeleted(oldSwitcher.getDeleted());
                    switcher.setHostId(oldSwitcher.getHostId());
                    switcher.setVendorId(vendorId);
                    switcher.setVdcId(vdcId);
                    BeanUtils.copyProperties(switcher, oldSwitcher, "guid");
                    if (StringUtils.isEmpty(oldSwitcher.getGuid())) {
                        oldSwitcher.setGuid(IDFactory.instance().uuid());
                    }
                    switcherRepository.update(oldSwitcher);
                    switcherGuid = oldSwitcher.getGuid();
                    switcherId = oldSwitcher.getId();
                    // 移除存在更新的交换机
                    oldMap.remove(switcher.getSwitcherVal());
                    infos.add(CmdbInfoConvertor.getInfo(oldSwitcher, null, relations, CloudProvider.VMWARE));
                } else {
                    switcher.preSave(managerId, managerId, vendorId, vdcId, hostId);
                    switcherRepository.save(switcher);
                    switcherGuid = switcher.getGuid();
                    switcherId = switcher.getId();
                    infos.add(CmdbInfoConvertor.getInfo(switcher, null, relations, CloudProvider.VMWARE));
                }
                // 同步该交换机下的端口组
                List<PortGroup> groups = portGroupRepository.listBySwitcher(switcherId);
                syncPortGroup(groups, switcher.getGroups(), vendorId, switcherId, managerId, switcher.getType(), infos,
                        switcherGuid);
            }
            // 删除不存在的交换机
            Iterator<Switcher> switchers = oldMap.values().iterator();
            while (switchers.hasNext()) {
                Switcher switcher = switchers.next();
                Long switcherId = switcher.getId();
                // cmdb删除虚拟机数据
                infos.add(CmdbInfoConvertor.getInfo(switcher, "delete", null, CloudProvider.VMWARE));
                networkCardRepository.release(switcherId, managerId);
                portGroupRepository.removeBySwitcher(switcherId, managerId);
                switcherRepository.remove(switcherId, managerId);
            }
        }
    }

    private void syncPortGroup(List<PortGroup> oldGroups, List<PortGroup> newGroups, Long vendorId, Long switcherId,
                               Long managerId, String switchType, List<CmdbInfo> infos, String switcherGuid) throws Exception {
        if (!ListTool.isEmpty(oldGroups) && ListTool.isEmpty(newGroups)) {
            List<PortGroup> groups = portGroupRepository.listBySwitcher(switcherId);
            for (PortGroup group : groups) {
                // cmdb删除虚拟机数据
                infos.add(CmdbInfoConvertor.getInfo(group, "delete", null, CloudProvider.VMWARE));
                ipPoolPortGroupRepository.deleteByGroupId(group.getId());
            }
            portGroupRepository.removeBySwitcher(switcherId, managerId);
        } else if (!ListTool.isEmpty(oldGroups) && !ListTool.isEmpty(newGroups)) {
            switch (NetworkType.SwitchType.valueOf(switchType)) {
                case VSWITCH:
                    // 该标准交换机下的端口组
                    Map<String, PortGroup> oldVswitchMap = Maps.newHashMap();
                    for (PortGroup group : oldGroups) {
                        oldVswitchMap.put(group.getName(), group);
                    }
                    for (PortGroup group : newGroups) {
                        // 虚拟机与对象的关系
                        List<CmdbRelation> relations = new ArrayList<>();
                        relations.add(new CmdbRelation(ModuleCode.VC_SWITCH.name(), 2L, ListUtils.getList(switcherGuid)));
                        if (oldVswitchMap.containsKey(group.getName())) {
                            PortGroup oldGroup = oldVswitchMap.get(group.getName());
                            group.setId(oldGroup.getId());
                            group.setGmtCreate(oldGroup.getGmtCreate());
                            group.setGmtModify(new Date());
                            group.setCreatorId(oldGroup.getCreatorId());
                            group.setMenderId(managerId);
                            group.setVendorId(vendorId);
                            group.setSwitcherId(oldGroup.getSwitcherId());
                            group.setType(oldGroup.getType());
                            group.setDeleted(oldGroup.getDeleted());
                            BeanUtils.copyProperties(group, oldGroup, "guid");
                            if (StringUtils.isEmpty(oldGroup.getGuid())) {
                                oldGroup.setGuid(IDFactory.instance().uuid());
                            }
                            portGroupRepository.update(oldGroup);
                            oldVswitchMap.remove(group.getName());
                            infos.add(CmdbInfoConvertor.getInfo(oldGroup, null, relations, CloudProvider.VMWARE));
                        } else {
                            group.preSave(managerId, managerId, vendorId, switcherId);
                            portGroupRepository.save(group);
                            infos.add(CmdbInfoConvertor.getInfo(group, null, relations, CloudProvider.VMWARE));
                        }
                    }
                    // 删除不存在的端口组
                    Iterator<PortGroup> vswitchGroups = oldVswitchMap.values().iterator();
                    while (vswitchGroups.hasNext()) {
                        PortGroup group = vswitchGroups.next();
                        // cmdb删除虚拟机数据
                        infos.add(CmdbInfoConvertor.getInfo(group, "delete", null, CloudProvider.VMWARE));
                        portGroupRepository.remove(group.getId(), managerId);
                        ipPoolPortGroupRepository.deleteByGroupId(group.getId());
                    }
                    break;
                case DVSWITCH:
                    Map<String, PortGroup> oldDvswitchMap = Maps.newHashMap();
                    for (PortGroup group : oldGroups) {
                        oldDvswitchMap.put(group.getGroupVal(), group);
                    }
                    for (PortGroup group : newGroups) {
                        // 虚拟机与对象的关系
                        List<CmdbRelation> relations = Lists.newArrayList();
                        relations.add(new CmdbRelation(ModuleCode.VC_SWITCH.name(), 2L, ListUtils.getList(switcherGuid)));
                        if (oldDvswitchMap.containsKey(group.getGroupVal())) {
                            PortGroup oldGroup = oldDvswitchMap.get(group.getGroupVal());
                            group.setId(oldGroup.getId());
                            group.setGmtCreate(oldGroup.getGmtCreate());
                            group.setGmtModify(new Date());
                            group.setCreatorId(oldGroup.getCreatorId());
                            group.setMenderId(managerId);
                            group.setVendorId(vendorId);
                            group.setSwitcherId(oldGroup.getSwitcherId());
                            group.setType(oldGroup.getType());
                            group.setDeleted(oldGroup.getDeleted());
                            BeanUtils.copyProperties(group, oldGroup, "guid");
                            if (StringUtils.isEmpty(oldGroup.getGuid())) {
                                oldGroup.setGuid(IDFactory.instance().uuid());
                            }
                            portGroupRepository.update(oldGroup);
                            // 移除存在更新的端口组
                            oldDvswitchMap.remove(group.getGroupVal());
                            infos.add(CmdbInfoConvertor.getInfo(oldGroup, null, relations, CloudProvider.VMWARE));
                        } else {
                            group.preSave(managerId, managerId, vendorId, switcherId);
                            portGroupRepository.save(group);
                            infos.add(CmdbInfoConvertor.getInfo(group, null, relations, CloudProvider.VMWARE));
                        }
                    }
                    // 删除不存在的端口组
                    Iterator<PortGroup> dvswitchGroups = oldDvswitchMap.values().iterator();
                    while (dvswitchGroups.hasNext()) {
                        PortGroup group = dvswitchGroups.next();
                        // cmdb删除虚拟机数据
                        infos.add(CmdbInfoConvertor.getInfo(group, "delete", null, CloudProvider.VMWARE));
                        portGroupRepository.remove(group.getId(), managerId);
                        ipPoolPortGroupRepository.deleteByGroupId(group.getId());
                    }
                    break;
                default:
                    break;
            }
        } else if (ListTool.isEmpty(oldGroups) && !ListTool.isEmpty(newGroups)) {
            for (PortGroup group : newGroups) {
                // 虚拟机与对象的关系
                List<CmdbRelation> relations = Lists.newArrayList();
                relations.add(new CmdbRelation(ModuleCode.VC_SWITCH.name(), 2L, ListUtils.getList(switcherGuid)));
                group.preSave(managerId, managerId, vendorId, switcherId);
                portGroupRepository.save(group);
                infos.add(CmdbInfoConvertor.getInfo(group, null, relations, CloudProvider.VMWARE));
            }
        }
    }

    /***
     * 同步网络
     * @param oldNetworks
     * @param newNetworks
     * @param vendorId
     * @param vdcId
     * @param managerId
     * @param networkMap
     * @param dvswitchMap
     * @param infos
     * @param vdcGuid
     * @throws Exception
     */
    public void syncNetwork(List<Network> oldNetworks, List<Network> newNetworks, Long vendorId, Long vdcId,
                            Long managerId, Map<String, Network> networkMap, Map<String, Long> dvswitchMap, List<CmdbInfo> infos, String vdcGuid) throws Exception {
        if (!ListTool.isEmpty(newNetworks)) {// 数据库存在，该数据中心下存在网络，则全部新增更新或删除
            Map<String, Network> oldMap = Maps.newHashMap();
            for (Network network : oldNetworks) {
                oldMap.put(network.getNetworkVal(), network);
            }
            // 不存在此网络则新增，否则更新
            for (Network network : newNetworks) {
                List<CmdbRelation> relations = Lists.newArrayList();
                relations.add(new CmdbRelation(ModuleCode.VC_DC.name(), 1L, ListUtils.getList(vdcGuid)));
                if (oldMap.containsKey(network.getNetworkVal())) {
                    Network oldNetwork = oldMap.get(network.getNetworkVal());
                    oldNetwork.setName(network.getName());
                    oldNetwork.setStatus(network.getStatus());
                    oldNetwork.setPortNum(network.getPortNum());
                    oldNetwork.setSwitcherId(dvswitchMap.get(network.getNetworkVal()));
                    oldNetwork.setMenderId(managerId);
                    oldNetwork.setOpaqueNetworkType(network.getOpaqueNetworkType());
                    networkRepository.update(oldNetwork);
                    networkMap.put(oldNetwork.getNetworkVal(), oldNetwork);
                    // 移除存在更新的网络
                    oldMap.remove(network.getNetworkVal());
                    // CMDB更新集群数据
                    if (null != infos) {
                        infos.add(CmdbInfoConvertor.getInfo(oldNetwork, null, relations, CloudProvider.VMWARE));
                    }
                } else {
                    network.preSave(managerId, managerId, vendorId, vdcId);
                    network.setSwitcherId(dvswitchMap.get(network.getNetworkVal()));
                    networkRepository.save(network);
                    networkMap.put(network.getNetworkVal(), network);
                    // CMDB添加集群数据
                    if (null != infos) {
                        infos.add(CmdbInfoConvertor.getInfo(network, null, relations, CloudProvider.VMWARE));
                    }
                }
            }
            // 删除不存在的网络
            Iterator<Network> networks = oldMap.values().iterator();
            while (networks.hasNext()) {
                networkRepository.remove(networks.next().getId(), managerId);
            }
        } else {// 数据库存在，该数据中心不存在网络，则全部删除
            for (Network network : oldNetworks) {
                networkHostRepository.deleteByNetwork(network.getId());
                // cmdb：删除网络
                if (null != infos) {
                    infos.add(CmdbInfoConvertor.getInfo(network, "delete", null, CloudProvider.VMWARE));
                }
            }
            networkRepository.removeByVdc(vdcId, managerId);
        }
    }

    /***
     * 同步数据存储
     * @param storeMap
     * @param oldStores
     * @param newStores
     * @param vendorId
     * @param vdcId
     * @param managerId
     * @param infos
     * @param vdcGuid
     * @throws Exception
     */
    private void syncStore(Map<String, DataStore> storeMap, List<DataStore> oldStores, List<DataStore> newStores,
                           Long vendorId, Long vdcId, Long managerId, List<CmdbInfo> infos, String vdcGuid)
            throws Exception {
        if (ListTool.isEmpty(oldStores) && !ListTool.isEmpty(newStores)) {// 数据库不存在，该虚拟机下存在快照，则全部新增
            // 新增
            for (DataStore dataStore : newStores) {
                Long clusterId = null;
                if (null != dataStore.getCluster()) {
                    Cluster newCluster = dataStore.getCluster();
                    Cluster oldCluster = clusterRepository.getByVal(newCluster.getClusterVal(), vdcId);
                    if (null == oldCluster) {
                        newCluster.setCategory("DATASTORE");
                        newCluster.setType(CloudProvider.VMWARE.name());
                        newCluster.setGmtCreate(new Date());
                        newCluster.preSave(managerId, managerId, vendorId, vdcId);
                        clusterRepository.save(newCluster);
                        clusterId = newCluster.getId();
                    } else {
                        clusterId = oldCluster.getId();
                    }
                }
                List<CmdbRelation> relations = Lists.newArrayList();
                relations.add(new CmdbRelation(ModuleCode.VC_DC.name(), 1L, ListUtils.getList(vdcGuid)));
                dataStore.preSave(managerId, managerId, vendorId, vdcId);
                dataStore.setDistributableRatio(BigDecimal.valueOf(100));
                dataStore.setClusterId(clusterId);
                dataStoreRepository.save(dataStore);
                storeMap.put(dataStore.getStoreVal(), dataStore);
                // cmdb添加数据存储数据
                infos.add(CmdbInfoConvertor.getInfo(dataStore, null, relations, CloudProvider.VMWARE));
            }
        } else if (!ListTool.isEmpty(oldStores) && !ListTool.isEmpty(newStores)) {// 数据库存在，该虚拟机下存在快照，则全部新增更新或删除
            Map<String, DataStore> oldStore = Maps.newHashMap();
            for (DataStore store : oldStores) {
                oldStore.put(store.getStoreVal(), store);
            }
            // 同步数据存储更新新增
            for (DataStore dataStore : newStores) {
                Long clusterId = null;
                if (null != dataStore.getCluster()) {
                    Cluster newCluster = dataStore.getCluster();
                    Cluster oldCluster = clusterRepository.getByVal(newCluster.getClusterVal(), vdcId);
                    if (null == oldCluster) {
                        newCluster.setCategory("DATASTORE");
                        newCluster.setType(CloudProvider.VMWARE.name());
                        newCluster.setGmtCreate(new Date());
                        newCluster.preSave(managerId, managerId, vendorId, vdcId);
                        clusterRepository.save(newCluster);
                        clusterId = newCluster.getId();
                    } else {
                        clusterId = oldCluster.getId();
                    }
                }
                List<CmdbRelation> relations = Lists.newArrayList();
                relations.add(new CmdbRelation(ModuleCode.VC_DC.name(), 1L, ListUtils.getList(vdcGuid)));
                relations.add(new CmdbRelation(ModuleCode.VC_DC.name(), 2L, ListUtils.getList(vdcGuid)));
                if (oldStore.containsKey(dataStore.getStoreVal())) {
                    DataStore store = oldStore.get(dataStore.getStoreVal());
                    store.setName(dataStore.getName());
                    store.setCapacity(dataStore.getCapacity());
                    store.setFreeSpace(dataStore.getFreeSpace());
                    store.setVdcId(vdcId);
                    store.setMenderId(managerId);
                    store.setHostNum(dataStore.getHostNum());
                    store.setVmNum(dataStore.getVmNum());
                    store.setTemplateNum(dataStore.getTemplateNum());
                    store.setStatus(dataStore.getStatus());
                    BigDecimal distributableRatio = store.getDistributableRatio();
                    if (null == distributableRatio) {
                        store.setDistributableRatio(BigDecimal.valueOf(100));
                    }
                    store.setClusterId(clusterId);
                    dataStoreRepository.update(store);
                    storeMap.put(store.getStoreVal(), store);
                    // 移除存在更新的数据存储
                    oldStore.remove(dataStore.getStoreVal());
                    // CMDB添加数据存储数据
                    infos.add(CmdbInfoConvertor.getInfo(store, null, relations, CloudProvider.VMWARE));
                } else {
                    dataStore.preSave(managerId, managerId, vendorId, vdcId);
                    dataStore.setDistributableRatio(BigDecimal.valueOf(100));
                    dataStore.setClusterId(clusterId);
                    dataStoreRepository.save(dataStore);
                    storeMap.put(dataStore.getStoreVal(), dataStore);
                    // CMDB更新数据存储数据
                    infos.add(CmdbInfoConvertor.getInfo(dataStore, null, relations, CloudProvider.VMWARE));
                }
            }
            // 同步数据存储删除不存在于平台上的数据
            Iterator<DataStore> stores = oldStore.values().iterator();
            while (stores.hasNext()) {
                DataStore store = stores.next();
                // cmdb删除数据存储数据
                infos.add(CmdbInfoConvertor.getInfo(store, "delete", null, CloudProvider.VMWARE));
                // 删除数据存储与主机关机
                storeHostRepository.deleteByStore(store.getId());
                dataStoreRepository.remove(store.getId(), managerId);
            }
        } else if (!ListTool.isEmpty(oldStores) && ListTool.isEmpty(newStores)) {// 数据库存在，该虚拟机不存在快照，则全部删除
            for (DataStore store : oldStores) {
                // cmdb删除数据存储数据
                infos.add(CmdbInfoConvertor.getInfo(store, "delete", null, CloudProvider.VMWARE));
                storeHostRepository.deleteByStore(store.getId());
            }
            dataStoreRepository.removeByVdc(vdcId, managerId);
        }
    }


    /***
     * 同步宿主机
     * @param vendor
     * @param vdc
     * @param cluster
     * @param data
     * @param managerId
     * @return
     * @throws Exception
     */
    public BocloudResult syncHostByCluster(CloudVendor vendor, Vdc vdc, Cluster cluster, Object data, Long managerId) throws Exception {
        CmdbModel model = new CmdbModel();
        model.setUuid(IDFactory.instance().uuid());
        model.setServiceName(BoCloudService.IMS.name());
        model.setManagerId(managerId);
        List<CmdbInfo> infos = Lists.newArrayList();
        // 添加云平台数据
        infos.add(CmdbInfoConvertor.getInfo(vendor, null, null, CloudProvider.VMWARE));
        List<IpPool> ipPools = ipPoolRepository.listByIpVersion(null);
        try {
            if (null != data) {
                Long vendorId = vendor.getId();
                String vendorGuid = vendor.getGuid();
                Long clusterId = cluster.getId();
                String clusterGuid = cluster.getGuid();
                Long vdcId = vdc.getId();
                String vdcGuid = vdc.getGuid();
                //获取数据中心下存储和网络
                List<DataStore> stores = dataStoreRepository.listByVdc(vdcId);
                Map<String, DataStore> storeMap = new HashMap<>();
                for (DataStore store : stores) {
                    storeMap.put(store.getStoreVal(), store);
                }

                List<Network> networks = networkRepository.listByVdc(vdcId);
                Map<String, Network> networkMap = Maps.newHashMap();
                for (Network network : networks) {
                    networkMap.put(network.getNetworkVal(), network);
                }

                // 获取分布式交换机
                List<Switcher> switcherList = switcherRepository.listByVdc(vdcId, "DVSWITCH");
                Map<String, String> groupMap = Maps.newHashMap();
                switcherList = switcherRepository.listByVdc(vdcId, "DVSWITCH");
                for (Switcher switcher : switcherList) {
                    List<PortGroup> groups = portGroupRepository.listBySwitcher(switcher.getId());
                    for (PortGroup group : groups) {
                        groupMap.put(group.getGroupVal(), switcher.getSwitcherVal());
                    }
                }
                // 获取集群下原有宿主机
                List<Server> oldHosts = serverRepository.listByCluster(clusterId);
                Map<String, Server> oldHostMap = Maps.newHashMap();
                for (Server oldHost : oldHosts) {
                    oldHostMap.put(oldHost.getUuid() + oldHost.getManageIp(), oldHost);
                }

                // 获取同步数据
                String content = JSONObject.toJSONString(data);
                List<HostSystem> hosts = JSONObject.parseArray(content, HostSystem.class);
                for (HostSystem host : hosts) {
                    // 宿主机与对象的关系
                    List<CmdbRelation> relations = Lists.newArrayList();
                    if (StringUtils.isEmpty(clusterGuid)) {
                        relations.add(new CmdbRelation(ModuleCode.VC_DC.name(), 1L, ListUtils.getList(vdcGuid)));
                    } else {
                        relations.add(new CmdbRelation(ModuleCode.VC_CLUSTER.name(), 1L, ListUtils.getList(clusterGuid)));
                    }
                    relations.add(new CmdbRelation(ModuleCode.VC_DC.name(), 2L, ListUtils.getList(vdcGuid)));
                    // cmdb:宿主机与数据存储关系
                    List<String> guids = Lists.newArrayList();
                    for (String store : host.getStores()) {
                        if (storeMap.containsKey(store)) {
                            guids.add(storeMap.get(store).getGuid());
                        }
                    }
                    relations.add(new CmdbRelation(ModuleCode.VC_DS.name(), 1L, guids));
                    // cmdb:宿主机与网络关系
                    List<String> networkGuids = Lists.newArrayList();
                    Map<String, Network> netMap = Maps.newHashMap();
                    for (String key : networkMap.keySet()) {
                        netMap.put(key, networkMap.get(key));
                    }
                    if (!ListTool.isEmpty(host.getNetworks())) {
                        List<Network> nets = JSONArray.parseArray(JSONObject.toJSONString(host.getNetworks()), Network.class);
                        for (Network network : nets) {
                            String val = network.getNetworkVal();
                            if (netMap.containsKey(val)) {// 网络存在则直接保存,标准网络
                                networkGuids.add(netMap.get(val).getGuid());
                            } else if (groupMap.containsKey(val) && netMap.containsKey(groupMap.get(val))) {// 网络不存，且在端口组中，则是分布式网络
                                networkGuids.add(netMap.get(groupMap.get(val)).getGuid());
                                netMap.remove(groupMap.get(val));
                            }
                        }
                    }
                    relations.add(new CmdbRelation(ModuleCode.VC_NETWORK.name(), 2L, networkGuids));
                    Long hostId = null;
                    // 更新宿主机以及相关实体对象
                    if (oldHostMap.containsKey(host.getUuid() + host.getHostIp())) {
                        Server server = oldHostMap.get(host.getUuid() + host.getHostIp());
                        hostId = server.getId();
                        // 同步主机标准交换机
                        List<Switcher> switchers = switcherRepository.listByHostId(hostId);
                        syncSwitcher(switchers, JSONArray.parseArray(JSONObject.toJSONString(host.getSwitchers()), Switcher.class), vendorId, vdcId, hostId, managerId, "VSWITCH", infos,
                                vendorGuid);
                        switchers = switcherRepository.listByHostId(hostId);
                        Map<String, Long> switcherMap = Maps.newHashMap();
                        for (Switcher switcher : switchers) {
                            switcherMap.put(switcher.getName(), switcher.getId());
                        }
                        // 更新宿主机
                        utils.mergeHost(server, host, vendorId, vdcId, clusterId, managerId, storeMap, networkMap, groupMap,
                                switcherMap, ipPools);
                        // 移除存在更新的宿主机
                        oldHostMap.remove(host.getUuid() + host.getHostIp());
                        // 同步集群节点
                        ClusterNode node = clusterNodeRepository.queryByRid(server.getResourceId());
                        if (null != node) {
                            if (null == clusterId) {
                                clusterNodeRepository.removeByRid(node.getResourceId(), managerId);
                            } else {
                                node.setClusterId(clusterId);
                                node.setMenderId(managerId);
                                node.setIp(server.getManageIp());
                                node.setStatus(server.getStatus());
                                clusterNodeRepository.update(node);
                            }
                        }
                        ServerConfig config = serverConfigRepository.getBySid(server.getId());
                        // cmdb更新宿主机数据
                        infos.add(CmdbInfoConvertor.getInfo(server, config, null, relations, CloudProvider.VMWARE));
//                        syncScsiLun(host.getScsiLunModels(), vendorId, hostId);
                    } else {
                        // 判断ipmi IP是否已存在
                        ServerConfig config = serverConfigRepository.getConfig(host.getIpmiAddress());
                        Server server = null;
                        if (null != config) {
                            config.setDiskCapacity(host.getDiskTotal());
                            config.setCpuHz(host.getCpuTotal());
                            config.setMemoryCapacity(host.getMemTotal());
                            config.setCpuAmount(host.getCpuNum());
                            config.setCpuMode(host.getCpuModel());
                            config.setCpuCore(host.getCpuCore());
                            config.setCpuUsed(host.getCpuUsed());
                            config.setMemUsed(host.getMemUsed());
                            config.setDiskUsed(host.getDiskUsed());
                            config.setVendor(host.getVendor());
                            config.setEsxVersion(host.getEsxVersion());
                            config.setEvc(host.getEvc());
                            config.setAssignedLicense(host.getAssignedLicense());
                            config.setIpmiAddress(host.getIpmiAddress());
                            config.setIpmiAccount(host.getIpmiAccount());
                            config.setIpmiPassword(host.getIpmiPassword());
                            config.setIpmiPort(623);
                            server = serverRepository.query(config.getServerId());
                            if (null == server) {
                                server = new Server();
                                BeanUtils.copyProperties(host, server);
                                server.setManageIp(host.getHostIp());
                                server.setResourceId(IDFactory.instance().uuid());
                                server.preSave(managerId, managerId, vendorId, vdcId, clusterId);
                                server.setOsCategory("ESXi");
                                server.setAssetCategory(ServerAssetCategory.HYPERVISOR.name());
                                serverRepository.save(server);
                                this.processIp(server.getVendorId(), server.getManageIp(), "PM", hostId, ipPools);
                                // 保存资源
                                List<String> privateIps = Lists.newArrayList();
                                privateIps.add(server.getManageIp());
                                Resource resource = new Resource(ResourceCategory.Computer.name(),
                                        ResourceCatalog.PHYSICAL.name(), server.getId(), JSONObject.toJSONString(privateIps),
                                        server.getCatalog(), vendorId);
                                resource.preSave(server.getName(), server.getStatus(), managerId, 0L);
                                resource.setInventory(JSONObject.toJSONString(server));
                                resourceRepository.save(resource);
                            } else {
                                BeanUtils.copyProperties(host, server);
                                server.setManageIp(host.getHostIp());
                                server.setVdcId(vdcId);
                                server.setClusterId(clusterId);
                                server.setVendorId(vendorId);
                                server.setMenderId(managerId);
                                server.setAssetCategory(ServerAssetCategory.HYPERVISOR.name());
                                serverRepository.update(server);
                                // 更新资源
                                Resource resource = resourceRepository.query(ResourceCategory.Computer.name(),
                                        ResourceCatalog.PHYSICAL.name(), server.getId());
                                List<String> privateIps = Lists.newArrayList();
                                privateIps.add(server.getManageIp());
                                if (null == resource) {
                                    resource = new Resource(ResourceCategory.Computer.name(), ResourceCatalog.LOGICAL.name(),
                                            server.getId(), JSONObject.toJSONString(privateIps), OSCategory.LINUX.name(),
                                            vendorId);
                                    resource.preSave(server.getName(), server.getPowerState(), managerId, 0L);
                                    resource.setInventory(JSONObject.toJSONString(server));
                                    resourceRepository.save(resource);
                                } else {
                                    resource.setStatus(server.getPowerState());
                                    resource.setPrivateIps(JSONObject.toJSONString(privateIps));
                                    resource.setMenderId(managerId);
                                    resourceRepository.update(resource);
                                }
                            }
                            hostId = server.getId();
                            config.setServerId(hostId);
                            serverConfigRepository.update(config);
                            server.setConfig(config);
                        } else {
                            server = new Server();
                            BeanUtils.copyProperties(host, server);
                            server.setManageIp(host.getHostIp());
                            server.setResourceId(IDFactory.instance().uuid());
                            server.preSave(managerId, managerId, vendorId, vdcId, clusterId);
                            server.setOsCategory("ESXi");
                            server.setAssetCategory(ServerAssetCategory.HYPERVISOR.name());
                            serverRepository.save(server);
                            hostId = server.getId();
                            // 保存主机配置信息
                            config = utils.addServerConfig(host, hostId);
                            server.setConfig(config);
                            // 处理IP地址
                            this.processIp(server.getVendorId(), server.getManageIp(), "PM", hostId, ipPools);
                            // 保存资源
                            List<String> privateIps = Lists.newArrayList();
                            privateIps.add(server.getManageIp());
                            Resource resource = new Resource(ResourceCategory.Computer.name(), ResourceCatalog.PHYSICAL.name(),
                                    server.getId(), JSONObject.toJSONString(privateIps), server.getCatalog(), vendorId);
                            resource.preSave(server.getName(), server.getStatus(), managerId, 0L);
                            resource.setInventory(JSONObject.toJSONString(server));
                            resourceRepository.save(resource);
//                            syncScsiLun(host.getScsiLunModels(), vendorId, hostId);
                        }
                        // 保存标准交换机
                        Map<String, Long> switcherMap = Maps.newHashMap();
                        List<Switcher> switchers = JSONArray.parseArray(JSONObject.toJSONString(host.getSwitchers()), Switcher.class);
                        for (Switcher switcher : switchers) {
                            switcher.preSave(managerId, managerId, vendorId, server.getVdcId(), hostId);
                            switcherRepository.save(switcher);
                            for (PortGroup group : switcher.getGroups()) {
                                group.preSave(managerId, managerId, vendorId, switcher.getId());
                                portGroupRepository.save(group);
                            }
                            switcherMap.put(switcher.getName(), switcher.getId());
                        }
                        // 保存物理网卡
                        utils.addCard(vendorId, hostId, managerId, "PM", JSONArray.parseArray(JSONObject.toJSONString(host.getNetcards()), NetworkCard.class), switcherMap);
                        // 宿主机和存储建立关系
                        utils.addStore(vendorId, hostId, managerId, "PM", host.getStores(), storeMap);
                        // 宿主机和网络建立关系
                        utils.addNetwork(vendorId, hostId, managerId, "PM", JSONArray.parseArray(JSONObject.toJSONString(host.getNetworks()), Network.class), networkMap, groupMap);
                        // 同步到集群节点
                        if (null != clusterId) {
                            ClusterNode node = new ClusterNode(server.getManageIp(), server.getResourceId(), "PM", clusterId);
                            node.setName(host.getName());
                            node.setCreatorId(managerId);
                            node.setMenderId(managerId);
                            node.setStatus(host.getStatus());
                            clusterNodeRepository.save(node);
                        }
                        // cmdb添加宿主机数据
                        infos.add(CmdbInfoConvertor.getInfo(server, config, null, relations, CloudProvider.VMWARE));
                    }
                }
                // 同步宿主机，删除不存在的宿主机
                logger.info("Remove hosts that does not exists");
                removeHost(oldHostMap, managerId, infos);
            }
            model.setData(infos);
            // 发送消息到cmdb模块，进行数据同步
            amqpTemplate.convertAndSend("cmdb.message.queue", JSONObject.parseObject(JSONObject.toJSONString(model)));
            return new BocloudResult(true, "云平台【 " + vendor.getName() + " 】主机集群【" + cluster.getName() + "】下宿主机数据同步成功");
        } catch (Exception e) {
            logger.error("Sync vdc error:", e);
            return new BocloudResult(false, "云平台【 " + vendor.getName() + " 】主机集群【" + cluster.getName() + "】下宿主机数据同步失败");
        }
    }

    /**
     * 处理ip地址
     *
     * @param vendorId
     * @param address
     * @param catalog
     * @param target
     * @param ipPools
     */
    private void processIp(Long vendorId, String address, String catalog, Long target, List<IpPool> ipPools) {
        Ip ip = ipRepository.checkExist(address, null, vendorId);
        if (null == ip) {
            ip = new Ip(address, null, null, null, vendorId, IDFactory.instance().uuid(), null, Ip.IpStatus.used);
            ip.setCatalog(catalog);
            ip.setTarget(target);
            for (IpPool pool : ipPools) {
                String dns = null;
                if (!org.apache.commons.lang3.StringUtils.isEmpty(pool.getDnsNames())) {
                    List<String> dnss = JSONArray.parseArray(pool.getDnsNames(), String.class);
                    if (!ListTool.isEmpty(dnss)) {
                        dns = dnss.get(0);
                    }
                }
                List<String> poolList = JSONArray.parseArray(pool.getPools(), String.class);
                IPAddress ipAddress = IPAddress.getIPAddress(address);
                boolean flag = ipAddress.isInPools(address, poolList);
                if (flag) {
                    ip.setMask(ipAddress.getMask(pool.getCidr()));
                    ip.setGateway(pool.getGateway());
                    ip.setDns(dns);
                    ip.setPoolId(pool.getId());
                    break;
                }
            }
            ipRepository.save(ip);
        } else {
            ip.setTarget(target);
            ip.setCatalog(catalog);
            ip.setStatus(Ip.IpStatus.used);
            ipRepository.update(ip);
        }
    }

    /**
     * 同步scsi lun
     *
     * @param models
     * @param vendorId
     * @param hostId
     * @throws Exception
     */
    private void syncScsiLun(List<ScsiLunModel> models, Long vendorId, Long hostId) throws Exception {
        if (ListTool.isEmpty(models)) {
            scsiLunRepository.removeByHostId(hostId);
            return;
        }
        List<ScsiLun> luns = scsiLunRepository.listByHostId(hostId);
        Map<String, ScsiLun> lunMap = new HashMap<>();
        for (ScsiLun lun : luns) {
            if (lunMap.containsKey(lun.getUuid())) {
                profileRepository.remove(lun.getId());
            } else {
                lunMap.put(lun.getUuid(), lun);
            }
        }
        for (ScsiLunModel model : models) {
            ScsiLun lun = new ScsiLun();
            if (lunMap.containsKey(model.getUuid())) {
                lun = lunMap.get(model.getUuid());
                BeanUtils.copyProperties(model, lun);
                scsiLunRepository.update(lun);
                lunMap.remove(model.getUuid());
                continue;
            }
            BeanUtils.copyProperties(model, lun);
            lun.setVendorId(vendorId);
            lun.setHostId(hostId);
            scsiLunRepository.save(lun);
            lunMap.remove(model.getUuid());
        }
        for (Entry<String, ScsiLun> entry : lunMap.entrySet()) {
            scsiLunRepository.remove(entry.getValue().getId());
        }
    }

    /**
     * 删除不存在的宿主机
     *
     * @param oldHostMap
     * @param managerId
     * @param infos
     * @throws Exception
     */
    private void removeHost(Map<String, Server> oldHostMap, Long managerId, List<CmdbInfo> infos) throws Exception {
        Iterator<Server> hosts = oldHostMap.values().iterator();
        while (hosts.hasNext()) {
            Server host = hosts.next();
            Long hostId = host.getId();
            storeHostRepository.deleteByHost(hostId, "PM");
            networkHostRepository.deleteByHost(hostId, "PM");
            networkCardRepository.removeByHost(hostId, "PM", managerId);
            List<Switcher> switchers = switcherRepository.listByHostId(hostId);
            for (Switcher switcher : switchers) {
                portGroupRepository.removeBySwitcher(switcher.getId(), managerId);
            }
            switcherRepository.removeByHostId(hostId, managerId);
            // cmdb删除宿主机
            infos.add(CmdbInfoConvertor.getInfo(host, null, "delete", null, CloudProvider.VMWARE));
            serverAssetsRepository.removeBySid(hostId);
            serverConfigRepository.removeBySid(hostId);
            resourceRepository.remove(hostId, ResourceCategory.Computer.name(), ResourceCatalog.PHYSICAL.name(),
                    managerId);
            serverRepository.remove(hostId, managerId);
            // 回收IP
            ipRepository.delete(host.getId(), "PM", host.getVendorId());
            // 删除集群节点
            clusterNodeRepository.removeByRid(host.getResourceId(), managerId);
            scsiLunRepository.removeByHostId(hostId);
        }
    }

    /***
     * 同步虚拟机下相关数据
     * @param vendor
     * @param vdc
     * @param host
     * @param data
     * @param managerId
     * @return
     * @throws Exception
     */
    public BocloudResult syncVmByHost(CloudVendor vendor, Vdc vdc, Server host, Object data, Long managerId) throws Exception {
        CmdbModel model = new CmdbModel();
        model.setUuid(IDFactory.instance().uuid());
        model.setServiceName(BoCloudService.IMS.name());
        model.setManagerId(managerId);
        List<CmdbInfo> infos = Lists.newArrayList();
        // 添加云平台数据
        infos.add(CmdbInfoConvertor.getInfo(vendor, null, null, CloudProvider.VMWARE));
        try {
            Long vendorId = vendor.getId();
            if (null != data) {
                String type = vendor.getType();
                Long vdcId = vdc.getId();
                Long hostId = host.getId();
                String serverGuid = host.getGuid();
                String status = host.getStatus();
                List<CloudServer> oldServers = cloudServerRepository.listByHid(hostId);
                Map<String, CloudServer> oldServerMap = Maps.newHashMap();
                for (CloudServer oldServer : oldServers) {
                    if (StringUtils.isEmpty(oldServer.getInstanceId())) {
                        oldServerMap.put(oldServer.getName(), oldServer);
                    } else {
                        if (oldServerMap.containsKey(oldServer.getInstanceId())) {
                            removeServerCascade(oldServerMap.get(oldServer.getInstanceId()), managerId, vendorId);
                            // cmdb删除虚拟机数据
                            infos.add(CmdbInfoConvertor.getInfo(oldServerMap.get(oldServer.getInstanceId()), "delete",
                                    null, CloudProvider.VMWARE));
                        }
                        oldServerMap.put(oldServer.getInstanceId(), oldServer);
                    }
                }
                // 获取同步数据
                String content = JSONObject.toJSONString(data);
                List<CloudServer> newServers = JSONObject.parseArray(content, CloudServer.class);
                if (!ListTool.isEmpty(newServers)) {
                    //获取数据中心下存储和网络
                    List<DataStore> stores = dataStoreRepository.listByVdc(vdcId);
                    Map<String, DataStore> storeMap = new HashMap<>();
                    for (DataStore store : stores) {
                        storeMap.put(store.getStoreVal(), store);
                    }
                    List<Network> networks = networkRepository.listByVdc(vdcId);
                    Map<String, Network> networkMap = Maps.newHashMap();
                    for (Network network : networks) {
                        networkMap.put(network.getNetworkVal(), network);
                    }
                    // 获取分布式交换机
                    List<Switcher> switcherList = switcherRepository.listByVdc(vdcId, "DVSWITCH");
                    Map<String, String> groupMap = Maps.newHashMap();
                    switcherList = switcherRepository.listByVdc(vdcId, "DVSWITCH");
                    for (Switcher switcher : switcherList) {
                        List<PortGroup> groups = portGroupRepository.listBySwitcher(switcher.getId());
                        for (PortGroup group : groups) {
                            groupMap.put(group.getGroupVal(), switcher.getSwitcherVal());
                        }
                    }
                    List<IpPool> pools = ipPoolRepository.listByIpVersion(null);
                    for (CloudServer cloudServer : newServers) {
                        // 虚拟机与对象的关系
                        List<CmdbRelation> relations = Lists.newArrayList();
                        relations.add(new CmdbRelation(ModuleCode.VC_PM.name(), 1L, ListUtils.getList(serverGuid)));
                        relations.add(new CmdbRelation(ModuleCode.VC_PM.name(), 2L, ListUtils.getList(serverGuid)));
                        // cmdb:虚拟机与数据存储关系
                        List<String> storeGuids = Lists.newArrayList();
                        if (!ListTool.isEmpty(cloudServer.getStores())) {
                            for (String store : cloudServer.getStores()) {
                                if (storeMap.containsKey(store)) {
                                    storeGuids.add(storeMap.get(store).getGuid());
                                }
                            }
                        }
                        relations.add(new CmdbRelation(ModuleCode.VC_DS.name(), 1L, storeGuids));
                        // cmdb:虚拟机与网络关系
                        List<String> networkGuids = Lists.newArrayList();
                        Map<String, Network> netMap = Maps.newHashMap();
                        for (String key : networkMap.keySet()) {
                            netMap.put(key, networkMap.get(key));
                        }
                        if (!ListTool.isEmpty(cloudServer.getNetworks())) {
                            for (Network network : cloudServer.getNetworks()) {
                                String val = network.getNetworkVal();
                                if (netMap.containsKey(val)) {// 网络存在则直接保存,标准网络
                                    networkGuids.add(netMap.get(val).getGuid());
                                } else if (groupMap.containsKey(val) && netMap.containsKey(groupMap.get(val))) {// 网络不存，且在端口组中，则是分布式网络
                                    networkGuids.add(netMap.get(groupMap.get(val)).getGuid());
                                    netMap.remove(groupMap.get(val));
                                }
                            }
                        }
                        relations.add(new CmdbRelation(ModuleCode.VC_NETWORK.name(), 2L, networkGuids));
                        if (oldServerMap.containsKey(cloudServer.getInstanceId())
                                || oldServerMap.containsKey(cloudServer.getName())) {
                            CloudServer server = null;
                            if (oldServerMap.containsKey(cloudServer.getInstanceId())) {
                                server = oldServerMap.get(cloudServer.getInstanceId());
                                // 移除存在更新的虚拟机
                                oldServerMap.remove(cloudServer.getInstanceId());
                            } else {
                                server = oldServerMap.get(cloudServer.getName());
                                // 移除存在更新的虚拟机
                                oldServerMap.remove(cloudServer.getName());
                            }
                            // 更新虚拟机
                            utils.mergeServer(server, cloudServer, status, vendorId, hostId, managerId, storeMap, networkMap,
                                    groupMap, type, pools);
                            // cmdb更新虚拟机数据
                            infos.add(CmdbInfoConvertor.getInfo(server, null, relations, CloudProvider.VMWARE));
                        } else {
                            cloudServer.setVendorType(type);
                            utils.addServerCascade(storeMap, cloudServer, vendorId, hostId, vdcId, managerId, status,
                                    networkMap, groupMap, type, pools);
                            // cmdb添加虚拟机数据
                            infos.add(CmdbInfoConvertor.getInfo(cloudServer, null, relations, CloudProvider.VMWARE));
                        }
                    }
                }
                // 删除当前云平台下不存在的虚拟机相关数据
                Iterator<CloudServer> removeServers = oldServerMap.values().iterator();
                while (removeServers.hasNext()) {
                    CloudServer removeServer = removeServers.next();
                    removeServerCascade(removeServer, managerId, vendorId);
                    // cmdb删除虚拟机数据
                    infos.add(CmdbInfoConvertor.getInfo(removeServer, "delete", null, CloudProvider.VMWARE));
                }
            }

            model.setData(infos);
            // 发送消息到cmdb模块，进行数据同步
            amqpTemplate.convertAndSend("cmdb.message.queue", JSONObject.parseObject(JSONObject.toJSONString(model)));
            return new BocloudResult(true, "云平台【 " + vendor.getName() + " 】宿主机【" + host.getName() + "】下虚拟机数据同步成功");
        } catch (Exception e) {
            logger.error("Sync vdc error:", e);
            return new BocloudResult(false, "云平台【 " + vendor.getName() + " 】主机集群【" + host.getName() + "】下宿主机数据同步失败");
        }
    }


    private void removeServerCascade(CloudServer server, Long managerId, Long vendorId) throws Exception {
        String status = server.getStatus();
        Long id = server.getId();
        if (BocloudStatus.Server.BUILDING.name().equals(status)) {
            return;
        }
        if (server.getIsTemplate()) {
            imageRepository.removeByTemplate(id, managerId);
        }
        snapshotTaskService.removeByVmId(id);
        snapshotRepository.removeByVm(id, managerId);
        storeHostRepository.deleteByHost(id, "VM");
        networkHostRepository.deleteByHost(id, "VM");
        networkCardRepository.removeByHost(id, "VM", managerId);
        resourceRepository.remove(id, ResourceCategory.Computer.name(), ResourceCatalog.LOGICAL.name(), managerId);
        cloudServerRepository.remove(id, managerId);
        tagRepository.removeByRes(vendorId, null, server.getInstanceId(), TagType.instance.name());
        // 回收IP
        ipRepository.makeFreeByTarget(server.getId(), "VM", vendorId);
        serverLabelRepository.deleteByTarget(id, "VM");
    }
}
