package com.bocloud.ims.service.resource;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.bocloud.cmp.model.ElasticIpGenericParam;
import com.bocloud.ims.entity.resource.*;
import com.bocloud.ims.interfaces.resource.*;
import com.bocloud.ims.repository.resource.*;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.compute.ServerDriver;
import com.bocloud.cmp.entity.enums.BocloudStatus;
import com.bocloud.cmp.entity.enums.CloudProvider;
import com.bocloud.cmp.entity.enums.ResourceCategory;
import com.bocloud.cmp.model.NotifyMessage;
import com.bocloud.cmp.model.ServerModel;
import com.bocloud.cmp.model.common.AlterationParam;
import com.bocloud.cmp.model.common.ApplicationParam;
import com.bocloud.cmp.model.common.CancelationParam;
import com.bocloud.cmp.model.common.DurationModel;
import com.bocloud.cmp.model.common.ElementModel;
import com.bocloud.cmp.model.common.EmptionModel;
import com.bocloud.cmp.model.common.ExtensionParam;
import com.bocloud.cmp.model.common.LocationModel;
import com.bocloud.cmp.model.common.OrderItem;
import com.bocloud.cmp.model.common.OrderMessage;
import com.bocloud.cmp.model.common.OrderMessage.Operation;
import com.bocloud.cmp.model.common.QuotaBean;
import com.bocloud.cmp.model.common.ResourceModel;
import com.bocloud.cmp.model.common.ServiceOrder;
import com.bocloud.cmp.model.common.SpecModel;
import com.bocloud.cmp.vm.model.VmGenericParam;
import com.bocloud.common.encrypt.AESEncrptor;
import com.bocloud.common.encrypt.Encryptor;
import com.bocloud.common.enums.BoCloudService;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.OperateResult;
import com.bocloud.common.model.OperateResult.OperateCategory;
import com.bocloud.common.model.RequestContext;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.DateTools;
import com.bocloud.common.utils.IDFactory;
import com.bocloud.common.utils.JSONTools;
import com.bocloud.common.utils.ListTool;
import com.bocloud.common.utils.MapTools;
import com.bocloud.ims.entity.common.Recycled;
import com.bocloud.ims.entity.resource.manageone.ManageOneAccount;
import com.bocloud.ims.entity.resource.nsx.NsxSegment;
import com.bocloud.ims.entity.resource.nsx.NsxTierOne;
import com.bocloud.ims.interfaces.manageone.ManageOneAccountService;
import com.bocloud.ims.repository.common.NsxSegmentRepository;
import com.bocloud.ims.repository.common.NsxTierOneRepository;
import com.bocloud.ims.service.builder.ServerBuilder;
import com.bocloud.ims.service.engine.ResSchedulerEngine;
import com.bocloud.ims.service.internal.CosInternalService;
import com.bocloud.ims.service.internal.worker.DiskFormatService;
import com.bocloud.ims.service.internal.worker.LvmService;
import com.bocloud.ims.service.model.ProcessResult;
import com.bocloud.ims.service.model.cmdb.CmdbInfo;
import com.bocloud.ims.service.utils.CmdbInfoConvertor;
import com.bocloud.ims.service.utils.CmdbMessagePublisher;
import com.bocloud.ims.service.utils.ResourceEventPublisher;
import com.bocloud.ims.service.utils.ServerOperationHelper;
import com.bocloud.ims.service.utils.SyncVmwareUtils;
import com.bocloud.nms.enums.OrderItemStatus;
import com.bocloud.service.lock.BocloudACLock;
import com.bocloud.service.lock.LockFactory;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
 * 虚拟机订购业务类实现类
 *
 * @author weiwei
 */
@Service("vmApplyService")
public class VMApplyServiceImpl implements VMApplyService {

    private static Logger logger = LoggerFactory.getLogger(VMApplyServiceImpl.class);
    private static OperateCategory operateCategory = OperateResult.OperateCategory.ResourceEvent;
    @Autowired
    private CloudServerRepository cloudServerRepository;
    @Autowired
    private CloudVendorRepository cloudVendorRepository;
    @Autowired
    private ImageRepository imageRepository;
    @Autowired
    private DataStoreRepository dataStoreRepository;
    @Autowired
    private ServerRepository serverRepository;
    @Autowired
    private LockFactory lockFactory;
    @Autowired
    private SnapshotRepository snapshotRepository;
    @Autowired
    private ServerDriver serverDriver;
    @Autowired
    private StoreHostRepository storeHostRepository;
    @Autowired
    private NetworkRepository networkRepository;
    @Autowired
    private PortGroupRepository portGroupRepository;
    @Autowired
    private NetworkHostRepository networkHostRepository;
    @Autowired
    private NetworkCardRepository networkCardRepository;
    @Autowired
    private ResourceRepository resourceRepository;
    @Autowired
    private IpRepository ipRepository;
    @Autowired
    private ObjectRelationRepository objectRelationRepository;
    @Autowired
    private VolumeRepository volumeRepository;
    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    private VdcRepository vdcRepository;
    @Autowired
    private ClusterRepository clusterRepository;
    @Autowired
    private CmdbMessagePublisher cmdbMessagePublisher;
    @Autowired
    private ServerOperationHelper serverOperationHelper;
    @Autowired
    private ServerConfigRepository serverConfigRepository;
    @Autowired
    private DiskFormatService diskFormatService;
    @Autowired
    private ResourceEventPublisher resourceEventPublisher;
    @Autowired
    private FlavorRepository flavorRepository;
    @Autowired
    private ManageOneAccountService accountService;
    @Autowired
    private IpService ipService;
    @Autowired
    private ResSchedulerEngine resSchedulerEngine;
    @Autowired
    private LvmService lvmService;
    @Autowired
    private CloudServerService cloudServerService;
    @Autowired
    private CosInternalService cosInternalService;
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;
    @Autowired
    private IpPoolRepository ipPoolRepository;
    @Autowired
    private NsxTierOneRepository tierOneRepository;
    @Autowired
    private NsxSegmentRepository segmentRepository;
    @Autowired
    private VendorProjectService vendorProjectService;
    @Autowired
    private ResourceEventRepository resourceEventRepository;
    @Autowired
    private PoolGroupRelationRepository poolGroupRelationRepository;
    @Autowired
    private LabelServiceImpl labelServiceImpl;
    @Autowired
    private SubnetRepository subnetRepository;
    @Autowired
    private NetworkInterfaceRepository networkInterfaceRepository;
    @Autowired
    private ElasticIpRepository elasticIpRepository;
    @Autowired
    private ElasticIpService elasticIpService;

    @Override
    public BocloudResult apply(ApplicationParam param) {
        try {
            Assert.notNull(param, "参数格式错误");
            ServiceOrder order = param.getOrder();
            Assert.notNull(order, "订单不存在");
            List<OrderItem> items = order.getItems();
            logger.info("订单明细：" + JSON.toJSONString(items));
            Assert.notEmpty(items, "订单明细不存在");
            List<ElementModel> elements = param.getElements();
            // 申请人
            RequestContext context = param.getContext();
            Assert.notNull(context, "申请人不存在");
            // 位置
            LocationModel location = param.getLocation();
            // 配置信息
            JSONObject configs = param.getConfigs();
            // 资源归属信息
            configs.put("poolGroupId", location.getPoolGroupId());
            configs.put("businessId", location.getBusinessId());
            configs.put("projectId", location.getProjectId());
            configs.put("creatorId", location.getCreatorId());
            configs.put("ownerId", location.getOwnerId());
            configs.put("menderId", location.getMenderId());
            String password = configs.getString("password");
            if (!StringUtils.isEmpty(password)) {
                Encryptor encryptor = new AESEncrptor();
                try {
                    password = encryptor.decrypt(password.trim(), null);
                    configs.put("password", password);
                } catch (Exception e) {
                    logger.error("Get error message:{}", e);
                    return new BocloudResult<>(false, e.getMessage());
                }
            }
            // 订购信息
            EmptionModel emption = param.getEmption();
            // 使用时长信息
            DurationModel duration = emption.getDuration();
            // 使用时长单位Hour/Month
            DurationModel.Mode mode = duration.getMode();
            // 时长
            Integer month = duration.getAmount();
            // 申请个数
            Integer count = null == emption.getCount() ? 1 : emption.getCount();
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(new Date());
            if (DurationModel.Mode.Hour == mode) {
                calendar.setTime(DateTools.stringToDateTime("2099-12-31 00:00:00"));
            } else {
                calendar.add(Calendar.MONTH, month);
            }
            CloudVendor vendor = cloudVendorRepository.query(location.getVendorId());
            Assert.notNull(vendor, "云平台不存在");
            CloudProvider provider = CloudProvider.valueOf(vendor.getType());
            // 通过调度策略分配的宿主机和存储
            String nsxNetworkName = null;
            List<JSONObject> targetObjs = new ArrayList<>();
            Map<Long, List<Ip>> networkConfigs = new HashMap<>();
            // 网卡端口组关联集合
            Map<Long, Long> portGroupConfigs = new HashMap<>();
            Long vpcId = configs.getLong("vpcId");
            if (CloudProvider.OPENSTACK == provider) {
                TenantProvider tenantProvider =
                    vendorProjectService.getAncestorProject(vendor.getId(), context.getTenant());
                Assert.notNull(tenantProvider, "租户云平台认证信息不存在");
            }
            if (CloudProvider.VMWARE == provider) {
                // vcenter从前端传的镜像id
                Long imageId = configs.getLong("imageId");
                if (null != imageId) {
                    Image targetImage = imageRepository.query(imageId);
                    Assert.notNull(targetImage, "未找到合适的镜像");
                    CloudServer template = cloudServerRepository.query(targetImage.getTemplateId());
                    Assert.notNull(template, "未找到合适的虚拟机模板");
                    configs.put("templateId", targetImage.getTemplateId());
                }
                BocloudResult<List<JSONObject>> BocloudResult = null;
                // 如果没有使用计算资源池，则默认按照随机策略分配宿主机和存储
                if (null != location.getPoolGroupId()) {
                    Map<String, Object> assignMap = Maps.newHashMap();
                    assignMap.put("Cpu", configs.getLong("cpu"));
                    assignMap.put("Memory", configs.getBigDecimal("memory"));
                    assignMap.put("Disk", configs.getLong("disk"));
                    assignMap.put("Instance", count);
                    // 根据计算资源池获取可分配宿主机，存储
                    BocloudResult = resSchedulerEngine.selectHost(location.getPoolGroupId(), "Cpu", assignMap,
                        configs.getString("diskCategory"));
                    // FIXME: 2021/5/11 自服务申请都会走地域可用域不会走到下面逻辑
                    // } else if (null != ipPoolId && 0L != ipPoolId) {
                    // IpPool ipPool = ipPoolRepository.query(ipPoolId);
                    // Assert.notNull(ipPool, "IP池不存在");
                    // Assert.notNull(ipPool.getVlanId(), "IP池未设置VLAN");
                    // BocloudResult = resSchedulerEngine.byVlan(vendor.getId(), ipPool.getVlanId(), count,
                    // configs.getString("diskCategory"), null);
                } else {
                    // nsx随机分配
                    BocloudResult =
                        resSchedulerEngine.byRandom(vendor.getId(), count, configs.getString("diskCategory"));
                    logger.info("nsx获取可分配宿主机");
                }
                Assert.isTrue(BocloudResult.isSuccess(), BocloudResult.getMessage());
                targetObjs = BocloudResult.getData();
                // 判断vcenter是否使用nsx网络
                if (null != vpcId) {
                    NsxTierOne tierOne = tierOneRepository.query(vpcId);
                    Assert.notNull(tierOne, "Tier1路由器不存在");
                    List<NsxSegment> segments = segmentRepository.listByConnectivityPath(tierOne.getPath());
                    for (NsxSegment segment : segments) {
                        nsxNetworkName = segment.getName();
                        BocloudResult<List<Ip>> achieveIpsData =
                            ipService.achieveNsxSegmentIps(segment.getId(), 1, "V4");
                        if (achieveIpsData.isFailed()) {
                            continue;
                        }
                        List<Ip> achieveIps = achieveIpsData.getData();
                        break;
                    }
                } else {
                    JSONArray ipConfigs =
                        Optional.ofNullable(configs.getJSONArray("networkCardConfigs")).orElse(new JSONArray());
                    for (int j = 0; j < ipConfigs.size(); j++) {
                        IpPool ipPool = null;
                        JSONObject config = ipConfigs.getJSONObject(j);
                        Long poolId = config.getLong("ipPoolId");
                        Long networkCardId = config.getLong("networkCardId");
                        Long portGroupId = config.getLong("portGroupId");
                        portGroupConfigs.put(networkCardId, portGroupId);
                        if (null != poolId && 0L != poolId) {
                            ipPool = ipPoolRepository.query(poolId);
                            Assert.notNull(ipPool, "IP池不存在");
                        }
                        switch (config.getString("ipPolicy")) {
                            case "Dhcp":
                                BocloudResult<List<Ip>> dhcpIpResult =
                                    ipService.achieveDhcpIps(poolId, count.longValue(), ipPool.getVersion());
                                Assert.isTrue(dhcpIpResult.isSuccess(), dhcpIpResult.getMessage());
                                List<Ip> dhcpIps = dhcpIpResult.getData();
                                networkConfigs.put(networkCardId, dhcpIps);
                                break;
                            case "Auto":
                                BocloudResult<List<Ip>> autoIpData =
                                    ipService.achievePoolIps(poolId, count.longValue(), ipPool.getVersion());
                                Assert.isTrue(autoIpData.isSuccess(), autoIpData.getMessage());
                                List<Ip> autoIps = autoIpData.getData();
                                networkConfigs.put(networkCardId, autoIps);
                                break;
                            case "Manual":
                                List<String> addresses = JSONArray
                                    .parseArray(JSONObject.toJSONString(config.getJSONArray("address")), String.class);
                                List<Ip> manualIps = ipRepository.listIpsByPool(poolId, addresses);
                                Assert.notEmpty(manualIps, "未设置正确的IP地址");
                                networkConfigs.put(networkCardId, manualIps);
                                break;
                            default:
                                break;
                        }
                    }
                }
                Assert.notNull(networkConfigs, "IP分配失败");
            }
            // 数据预处理结果
            List<ProcessResult> processResults = new ArrayList<>();
            // 数据预处理
            List<JSONObject> processObjs = new ArrayList<>();
            for (int i = 0; i < count; i++) {
                JSONObject newObj = JSONObject.parseObject(configs.toJSONString());
                // azure 虚拟机不支持下划线
                if (CloudProvider.AZURE == provider) {
                    newObj.put("name", configs.getString("name") + "-" + IDFactory.instance().mac());
                    newObj.put("systemDiskName",
                        configs.getString("systemDiskName") + "-" + IDFactory.instance().mac());
                } else {
                    newObj.put("name", configs.getString("name") + "_" + IDFactory.instance().mac());
                }
                if (!ListTool.isEmpty(targetObjs)) {
                    JSONObject targetObj = targetObjs.get(i);
                    newObj.put("storeId", targetObj.getLong("storeId"));
                    newObj.put("hostId", targetObj.getLong("hostId"));
                    // 数据盘分配存储
                    if (newObj.containsKey("addDiskList")) {
                        List<JSONObject> addDiskList =
                            JSONArray.parseArray(newObj.getString("addDiskList"), JSONObject.class);
                        if (!ListTool.isEmpty(addDiskList)) {
                            List<String> dataStoreNames =
                                resSchedulerEngine.assignStore(targetObj.getLong("hostId"), addDiskList);
                            if (ListTool.isEmpty(dataStoreNames)) {
                                return new BocloudResult<>(false, "为虚拟机分配数据盘存储发生错误");
                            }
                            newObj.put("dataStoreNames", dataStoreNames);
                            List<Integer> disks = new ArrayList<>();
                            for (JSONObject dataDisk : addDiskList) {
                                Integer disk = dataDisk.getInteger("disk");
                                disks.add(disk);
                            }
                            newObj.put("disks", disks);
                        }
                        newObj.put("dataDiskList", newObj.getString("addDiskList"));
                        newObj.remove("addDiskList");
                    }
                }
                processObjs.add(newObj);
            }
            for (int i = 0; i < processObjs.size(); i++) {
                JSONObject object = processObjs.get(i);
                object.put("expiredTime", calendar.getTime());
                BocloudResult<ServerBuilder> builderResult =
                    serverOperationHelper.getProcess(provider, vendor, context);
                if (builderResult.isFailed()) {
                    continue;
                }
                ServerBuilder process = builderResult.getData();
                BocloudResult<ProcessResult> result = null;
                if (CloudProvider.VMWARE == provider) {
                    Map<Long, Ip> ipMap = new HashMap<>();
                    for (Map.Entry<Long, List<Ip>> entry : networkConfigs.entrySet()) {
                        Long networkCardId = entry.getKey();
                        List<Ip> ips = entry.getValue();
                        Ip ip = ips.get(i);
                        ipMap.put(networkCardId, ip);
                    }
                    result = serverOperationHelper.prepareVcenter(object, param.getContext(), vendor, process, ipMap,
                        portGroupConfigs, nsxNetworkName);
                } else {
                    result = serverOperationHelper.prepare(
                        JSONObject.parseObject(object.toJSONString(), VmGenericParam.class), param.getContext(), vendor,
                        process);
                }
                Assert.isTrue(result.isSuccess(), result.getMessage());
                result.getData().setServerBuilder(process);
                processResults.add(result.getData());
            }
            // 配额
            List<QuotaBean> quotas = param.getQuotas();
            taskExecutor.execute(() -> {
                logger.info("Apply virtual machine start...");
                // 创建成功的虚拟机
                List<BocloudResult> succList = new ArrayList<>();
                // 创建失败的虚拟机
                List<BocloudResult> failList = new ArrayList<>();
                List<Future<BocloudResult<CloudServer>>> futures = new ArrayList<>();
                try {
                    // 执行创建虚拟机的操作
                    for (ProcessResult result : processResults) {
                        futures.add(
                            taskExecutor.submit(() -> serverOperationHelper.builder(vendor.getType(), vendor.getId(),
                                result.getCloudServer(), context, result.getServerBuilder(), param.getCallback())));
                    }
                    Map<String, List<OrderItem>> orderItemMap = new HashedMap();
                    List<OrderItem> list = null;
                    for (OrderItem orderItem : items) {
                        String serviceCode = orderItem.getServiceCode();
                        if (orderItemMap.containsKey(serviceCode)) {
                            list = orderItemMap.get(serviceCode);
                        } else {
                            list = new ArrayList<>();
                        }
                        list.add(orderItem);
                        orderItemMap.put(serviceCode, list);
                    }
                    String vmServiceCode = vendor.getType().toLowerCase() + ".standard.server";
                    // 获取线程池返回结果
                    for (int i = 0; i < futures.size(); i++) {
                        List<ResourceModel> resources = new ArrayList<>();
                        // 通知订单
                        OrderMessage message = null;
                        List<OrderItem> vmOrderItems = orderItemMap.get(vmServiceCode);
                        if (ListTool.isEmpty(vmOrderItems)) {
                            continue;
                        }
                        OrderItem item = vmOrderItems.get(0);
                        vmOrderItems.remove(item);
                        orderItemMap.put(vmServiceCode, vmOrderItems);

                        BocloudResult<CloudServer> result = futures.get(i).get();
                        CloudServer cloudServer = result.getData();
                        if (result.isSuccess()) {
                            ObjectRelation relation = new ObjectRelation(context.getTarget(), cloudServer.getId(),
                                false, ResourceCategory.Computer.name(), context.getCatalog().name(), 0);
                            relation.setExpiredTime(calendar.getTime());
                            objectRelationRepository.save(relation);
                            cloudServer.setUuid(item.getSn());
                            cloudServer.setGmtModify(new Date());
                            cloudServer.setExpiredTime(calendar.getTime());
                            cloudServer.setCategoryId(configs.getLong("categoryId"));
                            cloudServer.setSkuId(item.getSkuId());
                            // 存地域，可用域数据
                            cloudServer.setProps(JSONObject.toJSONString(location));
                            cloudServerRepository.update(cloudServer);

                            if (CloudProvider.AWS.name().equalsIgnoreCase(vendor.getType())) {
                                try {
                                    if (configs.getBoolean("hasIpv6")) {
                                        JSONArray privateIps = JSONArray.parseArray(cloudServer.getPrivateIps());
                                        Subnet subnet = subnetRepository.query(configs.getLong("subnetId"));
                                        String ipv6Cidr = subnet.getIpv6Cidr();
                                        logger.info("ipv6Cidr:" + ipv6Cidr);
                                        List<NetworkInterface> interfaces = networkInterfaceRepository.listByServerId(vendor.getId(),
                                                cloudServer.getId());
                                        if (ListTool.isEmpty(interfaces)) {
                                            logger.error("虚机网络接口不存在");
                                            resourceEventPublisher.send(new OperateResult(false, "虚机网络接口不存在",
                                                    vendor.getType().toLowerCase() + ".vm",
                                                    MapTools.simpleMap(Common.VENDORID, vendor.getId()), operateCategory, context));
                                        } else {
                                            String ipV6Address = ipv6Cidr.substring(0, ipv6Cidr.indexOf("/") - 1)
                                                    + privateIps.getString(0);
                                            ipV6Address = ipV6Address.replaceAll("\\.", ":");
                                            BocloudResult assignIpv6Result = new BocloudResult(false, "Ipv6分配失败");
                                            int num = 0;
                                            while (num < 60) {
                                                Thread.sleep(5000);
                                                assignIpv6Result = serverDriver.assignIpv6(vendor.getUuid(),
                                                        interfaces.get(0).getNetworkInterfaceUuid(), ipV6Address,
                                                        interfaces.get(0).getRegionId());
                                                if (assignIpv6Result.isSuccess()) {
                                                    break;
                                                }
                                                num++;
                                            }
                                            if (assignIpv6Result.isFailed()) {
                                                logger.error("虚机IpV6设置失败 {} ", assignIpv6Result.getMessage());
                                                resourceEventPublisher.send(new OperateResult(assignIpv6Result.isSuccess(),
                                                        "虚机IpV6设置失败", vendor.getType().toLowerCase() + ".vm",
                                                        MapTools.simpleMap(Common.VENDORID, vendor.getId()), operateCategory,
                                                        context));
                                            } else {
                                                // 回填IPv6
                                                privateIps.add(ipV6Address);
                                                cloudServer.setPrivateIps(privateIps.toJSONString());
                                                cloudServerRepository.update(cloudServer);
                                            }
                                        }
                                    }
                                } catch (Exception e) {
                                    logger.error("虚机IpV6设置失败 {} ", e.getMessage());
                                    resourceEventPublisher.send(
                                            new OperateResult(false, "虚机IpV6设置失败", vendor.getType().toLowerCase() + ".vm",
                                                    MapTools.simpleMap(Common.VENDORID, vendor.getId()), operateCategory, context));
                                }
                                try {
                                    if (configs.getBoolean("hasEip")) {
                                        Long eipId = configs.getLong("eipId");
                                        ElasticIp elasticIp = null;
                                        if (eipId == null) {
                                            ElasticIp elasticIpInfo = new ElasticIp();
                                            elasticIpInfo.setName("EIP_" + UUID.randomUUID());
                                            elasticIpInfo.setVendorId(vendor.getId());
                                            elasticIpInfo.setRegionId(configs.getString("regionId"));
                                            BocloudResult allocateResult = elasticIpService.allocate(elasticIpInfo, context);
                                            if (allocateResult.isFailed()) {
                                                logger.error("EIP分配失败 {} ", allocateResult.getMessage());
                                                resourceEventPublisher.send(new OperateResult(allocateResult.isSuccess(),
                                                        "EIP分配失败", vendor.getType().toLowerCase() + ".vm",
                                                        MapTools.simpleMap(Common.VENDORID, vendor.getId()), operateCategory,
                                                        context));
                                            } else {
                                                elasticIp = (ElasticIp) allocateResult.getData();
                                            }
                                        } else {
                                            elasticIp = elasticIpRepository.query(eipId);
                                        }
                                        if (null == elasticIp) {
                                            logger.error("EIP数据不存在");
                                            resourceEventPublisher.send(new OperateResult(false, "EIP数据不存在",
                                                    vendor.getType().toLowerCase() + ".vm",
                                                    MapTools.simpleMap(Common.VENDORID, vendor.getId()), operateCategory, context));
                                        } else {
                                            ElasticIpGenericParam elasticIpGenericParam = new ElasticIpGenericParam();
                                            elasticIpGenericParam.setId(elasticIp.getId());
                                            elasticIpGenericParam.setInstanceId(cloudServer.getInstanceId());
                                            elasticIpGenericParam.setAllowReassociation(true);
                                            BocloudResult associateResult = elasticIpService.associate(elasticIpGenericParam,
                                                    context);
                                            if (associateResult.isFailed()) {
                                                logger.error("虚机EIP关联失败 {} ", associateResult.getMessage());
                                                resourceEventPublisher.send(new OperateResult(associateResult.isSuccess(),
                                                        "虚机关联EIP失败", vendor.getType().toLowerCase() + ".vm",
                                                        MapTools.simpleMap(Common.VENDORID, vendor.getId()), operateCategory,
                                                        context));
                                            }

                                        }
                                    }
                                } catch (Exception e) {
                                    logger.error("虚机关联EIP失败 {} ", e.getMessage());
                                    resourceEventPublisher.send(
                                            new OperateResult(false, "虚机关联EIP失败", vendor.getType().toLowerCase() + ".vm",
                                                    MapTools.simpleMap(Common.VENDORID, vendor.getId()), operateCategory, context));
                                }
                            }

                            String resourceLabel = cloudServer.getResourceLabel();
                            if (!StringUtils.isEmpty(resourceLabel)) {
                                labelServiceImpl.saveServerLabel(cloudServer.getId(), "VM", cloudServer.getVendorId(),
                                    resourceLabel, context);
                            }
                            // 查询磁盘设备列表
                            List<Volume> volumes = volumeRepository.listByServerId(cloudServer.getId());
                            // 数据盘 + 系统盘
                            if (!ListTool.isEmpty(volumes)) {
                                String volumeServiceCode;
                                if ("VMWARE".equals(vendor.getType())) {
                                    volumeServiceCode = vendor.getType().toLowerCase() + ".storage.disk";
                                } else {
                                    volumeServiceCode = vendor.getType().toLowerCase() + ".standard.volume";
                                }
                                for (Volume volume : volumes) {
                                    String uuid = null;
                                    Long skuId = null;
                                    OrderItem orderItemValue = null;
                                    List<OrderItem> volumeOrderItems = orderItemMap.get(volumeServiceCode);
                                    if (!ListTool.isEmpty(volumeOrderItems)) {
                                        for (OrderItem orderItem : volumeOrderItems) {
                                            List<ElementModel> elementModels =
                                                JSON.parseArray(orderItem.getElements(), ElementModel.class);
                                            if (!ListTool.isEmpty(elementModels)) {
                                                List<SpecModel> specs = elementModels.get(0).getSpecs();
                                                if (!ListTool.isEmpty(specs)) {
                                                    SpecModel specModel = specs.get(0);
                                                    if (null != specModel
                                                        && specModel.getDisk().equals(volume.getSize())) {
                                                        orderItemValue = orderItem;
                                                        break;
                                                    }
                                                }
                                            }
                                        }
                                        // 后续需要加上过滤
                                        if (null != orderItemValue) {
                                            uuid = orderItemValue.getSn();
                                            skuId = orderItemValue.getSkuId();
                                            volume.setUuid(uuid);
                                            volume.setSkuId(orderItemValue.getSkuId());
                                            volumeOrderItems.remove(orderItemValue);
                                            orderItemMap.put(volumeServiceCode, volumeOrderItems);
                                        }
                                    }
                                    volume.setExpiredTime(cloudServer.getExpiredTime());
                                    volume.setMenderId(cloudServer.getMenderId());
                                    volume.setTenantId(cloudServer.getTenantId());
                                    volume.setProjectId(cloudServer.getProjectId());
                                    volume.setBusinessId(cloudServer.getBusinessId());
                                    volume.setOwnerId(cloudServer.getOwnerId());
                                    volume.setCreatorId(cloudServer.getCreatorId());
                                    volume.setSkuId(skuId);
                                    volumeRepository.update(volume);
                                    List<ResourceModel> volumeResources = new ArrayList<>();
                                    volumeResources.add(new ResourceModel(volume.getName(), volume.getVolumeUuid(),
                                    		orderItemValue.getServiceCode(), volume.getVolumeUuid(), volume.getUuid()));
                                    message = new OrderMessage(uuid, Operation.Application,
                                        OrderItemStatus.OpenedSuccess, null, "虚机硬盘申请成功", cloudServer.getGmtCreate(),
                                        calendar.getTime(), volumeResources, ResourceCategory.Storage.name(), context);
                                    message.setCategory(ResourceCategory.Storage.name());
                                    // 通知订单
                                    logger.info("结果消息发送 ： " + JSON.toJSONString(message));
                                    amqpTemplate.convertAndSend("resource.result.queue", message);
                                }
                            }
                            BocloudResult bocloudResult = new BocloudResult<>(true,
                                "【" + cloudServer.getName() + "】创建成功【" + result.getMessage() + "】");
                            succList.add(bocloudResult);
                            resources.add(new ResourceModel(cloudServer.getName(), cloudServer.getInstanceId(),
                                param.getService(), cloudServer.getInstanceId(), cloudServer.getUuid()));
                            message = new OrderMessage(item.getSn(), Operation.Application,
                                OrderItemStatus.OpenedSuccess, null, "虚拟机申请创建成功", cloudServer.getGmtCreate(),
                                calendar.getTime(), resources, ResourceCategory.Computer.name(), context);
                            message.setCategory(ResourceCategory.Computer.name());
                            // 通知订单
                            logger.info("结果消息发送 ： " + JSON.toJSONString(message));
                            amqpTemplate.convertAndSend("resource.result.queue", message);
                        } else {
                            // 磁盘失败回调
                            String volumeServiceCode;
                            if ("VMWARE".equals(vendor.getType())) {
                                volumeServiceCode = vendor.getType().toLowerCase() + ".storage.disk";
                            } else {
                                volumeServiceCode = vendor.getType().toLowerCase() + ".standard.volume";
                            }
                            List<OrderItem> volumeOrderItems = orderItemMap.get(volumeServiceCode);
                            for (OrderItem volumeOrderItem : volumeOrderItems) {
                                OrderMessage volumeMessage =
                                    new OrderMessage(volumeOrderItem.getSn(), Operation.Application,
                                        OrderItemStatus.OpenedFailure, null, "创建失败【" + result.getMessage() + "】", null,
                                        null, new ArrayList<>(), ResourceCategory.Computer.name(), context);
                                // 通知订单
                                logger.info("结果消息发送 ： " + JSON.toJSONString(volumeMessage));
                                amqpTemplate.convertAndSend("resource.result.queue", volumeMessage);
                            }
                            // 如果虚机存在直接删除
                            cloudServerRepository.remove(cloudServer.getId(), context.getTarget());
                            BocloudResult bocloudResult =
                                new BocloudResult<>(false, "创建失败【" + result.getMessage() + "】");
                            applyVmFailCallback(item.getSn(), bocloudResult, context, quotas, items.size());
                            failList.add(bocloudResult);
                        }
                    }
                } catch (Exception e) {
                    logger.error("apply virtual machine fail:", e);
                }
                // 发送给云平台统计队列对云平台重新统计
                JSONObject jsonObject = new JSONObject();
                jsonObject.put(Common.VENDORID, vendor.getId());
                amqpTemplate.convertAndSend("vendor.statistics.queue", jsonObject);
                logger.info("Apply virtual machine end");
            });
            return new BocloudResult<>(true, "申请任务已经下发，正在执行……");
        } catch (Exception e) {
            logger.error("Apply virtual machine error", e);
            return new BocloudResult<>(false, "申请虚拟机失败：" + e.getMessage());
        }
    }

    public void applyVmFailCallback(String sn, BocloudResult bocloudResult, RequestContext context,
        List<QuotaBean> quotas, int itemSize) {
        try {
            quotas = Optional.ofNullable(quotas).orElse(new ArrayList<>());
            OrderMessage message = new OrderMessage(sn, Operation.Application, OrderItemStatus.OpenedFailure, null,
                bocloudResult.getMessage(), null, null, new ArrayList<>(), ResourceCategory.Computer.name(), context);
            // 回滚配额
            List<QuotaBean> beans = new ArrayList<>();
            for (QuotaBean bean : quotas) {
                beans.add(new QuotaBean(bean.getCode(), bean.getValue() / itemSize));
            }
            message.setQuotas(beans);
            message.setCategory(ResourceCategory.Computer.name());
            // 通知订单
            logger.info("结果消息发送 ： " + JSON.toJSONString(message));
            amqpTemplate.convertAndSend("resource.result.queue", message);
        } catch (AmqpException e) {
            logger.error("申请虚机回滚配额失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult recycle(Long id, RequestContext context) {
        try {
            CloudServer server = cloudServerRepository.get(id);
            Optional.ofNullable(server).orElseThrow(() -> new Exception("虚拟机不存在"));
            CloudVendor vendor = cloudVendorRepository.query(server.getVendorId());
            Optional.ofNullable(vendor).orElseThrow(() -> new Exception("云平台不存在"));
            taskExecutor.execute(() -> {
                cloudServerRepository.recycle(id, context.getTarget());
                // 关机
                if (!BocloudStatus.Server.STOPPED.name().equalsIgnoreCase(server.getStatus())) {
                    BocloudResult result = cloudServerService.stop(id, context);
                    if (result.isSuccess()) {
                        // 等待关机成功，否则有些云平台的会删除不了
                        try {
                            waitTask(id);
                        } catch (Exception e) {
                            logger.error("Get error message:{}", e);
                        }
                    }
                }
                // 回收站生成记录
                String spec = server.getCpu() + "核/" + server.getMemory() + "GB/" + server.getDisk() + "GB";
                Recycled recycled = new Recycled(server.getName(), server.getUuid(),
                    ResourceCategory.Computer.name() + "-" + server.getVendorType(), server.getId(),
                    server.getProjectId(), server.getCatalog().name(), spec);
                recycled.setTenantId(server.getTenantId());
                recycled.setUserId(server.getOwnerId());
                recycled.setProjectId(server.getProjectId());
                recycled.setMenderId(server.getMenderId());
                recycled.setOwnerId(server.getOwnerId());
                logger.info("ims发送 recycled 数据到cos：{}", JSONObject.toJSON(recycled));
                BocloudResult joinRecycle = cosInternalService.joinRecycle(recycled);
                logger.info("生成回收站记录结果：{}", JSONObject.toJSON(joinRecycle));
                RequestContext requestContext = new RequestContext(server.getCatalog(), server.getTenantId(),
                    server.getCreatorId(), server.getProjectId(), null);
                // 发送站内信
                NotifyMessage notifyMessage = new NotifyMessage(requestContext, "虚拟机放入回收站通知",
                    "虚拟机【" + server.getName() + "】已关机放入回收站", true, false);
                amqpTemplate.convertAndSend("event.notice.queue", notifyMessage);
                String operate = vendor.getType().toLowerCase() + ".vm";
                OperateResult message = new OperateResult(true, "虚拟机【" + server.getName() + "】已关机放入回收站", operate,
                    MapTools.simpleMap(Common.VENDORID, vendor.getId()), OperateCategory.ResourceEvent, context);
                resourceEventPublisher.send(message);
            });
            return new BocloudResult<>(true, "虚拟机【" + server.getName() + "】加入回收站任务已下发，请耐心等待结果...");
        } catch (Exception e) {
            logger.error("remove CloudServer fail:", e);
            return new BocloudResult<>(false, "虚拟机删除失败");
        }
    }

    /**
     * 等待关机成功
     *
     * @param serverId
     * @throws Exception
     */
    private void waitTask(Long serverId) throws Exception {
        CloudServer server = cloudServerRepository.query(serverId);
        if (null == server) {
            return;
        }
        Boolean flag = true;
        Long startTime = System.currentTimeMillis();
        while (flag) {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                logger.error("Get error message:", e);
                Thread.currentThread().interrupt();
            }
            server = cloudServerRepository.query(serverId);
            if (null == server) {
                flag = false;
                break;
            }
            if (BocloudStatus.Server.STOPPED.name().equalsIgnoreCase(server.getStatus())) {
                flag = false;
                break;
            }
            Long endTime = System.currentTimeMillis();
            if (endTime - startTime > 60 * 1000 * 20) {
                flag = false;
                break;
            }
        }
    }

    @Override
    public BocloudResult restore(Long id, RequestContext context) {
        try {
            CloudServer server = cloudServerRepository.get(id);
            Optional.ofNullable(server).orElseThrow(() -> new Exception("虚拟机不存在"));
            CloudVendor vendor = cloudVendorRepository.query(server.getVendorId());
            Optional.ofNullable(vendor).orElseThrow(() -> new Exception("云平台不存在"));
            cloudServerRepository.restore(id, context.getTarget());
            cloudServerService.start(id, context);
            return new BocloudResult<>(true, "虚拟机【" + server.getName() + "】还原成功");
        } catch (Exception e) {
            logger.error("remove CloudServer fail:", e);
            return new BocloudResult<>(false, "虚拟机还原失败");
        }
    }

    @Override
    public List<CloudServer> getRecycleServers(Long vendorId) {
        try {
            return cloudServerRepository.listRecycle(vendorId);
        } catch (Exception e) {
            logger.error("list recycle server fail:", e);
            return Lists.newArrayList();
        }
    }

    @Override
    public BocloudResult alteration(AlterationParam alteration) {
        try {
        	
            RequestContext context = alteration.getContext();
            CloudServer server = cloudServerRepository.getByUuid(alteration.getInstance());
            Assert.notNull(server, "虚拟机不存在");
            CloudVendor vendor = cloudVendorRepository.query(server.getVendorId());
            Assert.notNull(vendor, "云平台不存在");
            // CPU
            Integer cpu = alteration.getCpu();
            // 内存
            BigDecimal memory = alteration.getMemory();
            // 磁盘
            Integer systemDisk = alteration.getSystemDisk();
            List<Volume> volumes = null;
            CloudProvider provider = CloudProvider.valueOf(vendor.getType());
            switch (provider) {
                case OPENSTACK:
                case MANAGEONE:
                case FUSIONCLOUD:
                    volumes = volumeRepository.listByServerId(server.getId(), vendor.getId(), true);
                    // 通过卷创建的虚拟机修改配置时只会修改cpu和内存大小
                    if (!ListTool.isEmpty(volumes)) {
                        systemDisk = server.getDisk();
                    }
                    JSONObject object = new JSONObject();
                    object.put("cpu", cpu);
                    object.put("memory", memory);
                    object.put("disk", systemDisk);
                    Flavor flavor = serverOperationHelper.getFlavorId(vendor.getId(), provider,
                        JSONObject.parseObject(object.toJSONString(), VmGenericParam.class));
                    if (null == flavor) {
                        flavor = serverOperationHelper.createFlavor(cpu, memory, systemDisk, context, vendor);
                        Assert.notNull(flavor, "该平台没有适配的规格");
                    }
                    BocloudResult flavorResult = null;
                    ManageOneAccount account = null;
                    if (CloudProvider.MANAGEONE.name().equals(vendor.getType()) && null != context.getTenant()
                        && 0L != context.getTenant()) {
                        account = accountService.queryAccount(vendor.getId(), context.getTenant());
                        Assert.notNull(account, "认证失败！");
                        flavorResult = serverDriver.resize(server.getInstanceId(), flavor.getFlavorUuid(),
                            vendor.getUuid(), account.getUsername(), account.getPassword(), account.getProjectId(),
                            account.getDomainName());
                    } else {
                        flavorResult =
                            serverDriver.resize(server.getInstanceId(), flavor.getFlavorUuid(), vendor.getUuid(), null);
                    }
                    if (flavorResult.isSuccess()) {
                        if (CloudProvider.MANAGEONE.name().equals(vendor.getType()) && null != context.getTenant()
                            && 0L != context.getTenant()) {
                            flavorResult = serverDriver.confirmResize(server.getInstanceId(), vendor.getUuid(),
                                account.getUsername(), account.getPassword(), account.getProjectId(),
                                account.getDomainName());
                        } else {
                            // 确认配置
                            flavorResult = serverDriver.confirmResize(server.getInstanceId(), vendor.getUuid(), null);
                        }
                        if (flavorResult.isFailed()) {
                            // 回滚
                            if (CloudProvider.MANAGEONE.name().equals(vendor.getType()) && null != context.getTenant()
                                && 0L != context.getTenant()) {
                                serverDriver.revertResize(server.getInstanceId(), vendor.getUuid(),
                                    account.getUsername(), account.getPassword(), account.getProjectId(),
                                    account.getDomainName());
                            } else {
                                serverDriver.revertResize(server.getInstanceId(), vendor.getUuid(), null);
                            }
                            return flavorResult;
                        }
                    } else {
                        return flavorResult;
                    }
                    server.setCpu(cpu);
                    server.setMemory(memory);
                    server.setGmtModify(new Date());
                    // 配置升级的时候 才修改uuid为虚拟机对应的订单sn
                    if (alteration.getOperation().equals(AlterationParam.Operation.Upgrade)) {
                        server.setUuid(alteration.getNewInstance());
                    }
                    if (null != alteration.getUpgradeSkuId()) {
                        server.setSkuId(alteration.getUpgradeSkuId());
                    }
                    cloudServerRepository.update(server);
                    break;
                case VMWARE:
                    Vdc vdc = vdcRepository.query(server.getVdcId());
                    Assert.notNull(vdc, "数据中心不存在");
                    Server host = serverRepository.query(server.getHostId());
                    Assert.notNull(host, "虚拟机所属主机不存在");
                    List<StoreHost> storeHosts = storeHostRepository.list(host.getId(), "PM");
                    Assert.notEmpty(storeHosts, "该虚拟机所属宿主机未绑定任何存储");
                    Map<Long, StoreHost> storageHostMap = storeHosts.stream().collect(Collectors.toMap(StoreHost::getStoreId, a -> a,(k1,k2)-> k2));
                    // 数据盘
                    List<JSONObject> addDataDisks = alteration.getAddDataDisks();
                    ServerModel model = new ServerModel(server.getName(), cpu, memory, null, server.getInstanceId());
                    model.setSystemDiskSize(systemDisk);
                    model.setVdcName(vdc.getName());
                    Long storeId = getaStoreId(server, storageHostMap);
                    DataStore datastore = dataStoreRepository.query(storeId);
                    model.setDatastore(datastore.getName());
                    // 虚拟机数据盘
                    if (!ListTool.isEmpty(addDataDisks)) {
                        List<Integer> disks = new ArrayList<>();
                        List<String> dataStoreNames = new ArrayList<>();
                        for (JSONObject dataDiskObj : addDataDisks) {
                            String category = dataDiskObj.getString("category");
                            Integer disk = dataDiskObj.getInteger("disk");
                            String dataDiskStore = null;
                            Long randomStoreId = getaStoreId(server, storageHostMap);
                            DataStore store = dataStoreRepository.query(randomStoreId);
                            if (null != store) {
                                dataDiskStore = store.getName();
                            }
                            if (StringUtils.isEmpty(dataDiskStore)) {
                                return new BocloudResult<>(false, "根据数据盘磁盘类型未找到合适的数据存储!");
                            }
                            disks.add(disk);
                            dataStoreNames.add(dataDiskStore);
                        }
                        model.setDisks(disks);
                        model.setDataStoreNames(dataStoreNames);
                    }
                    // 要编辑的虚拟机磁盘设备
                    model.setEditDiskList(alteration.getEditDataDisks());
                    BocloudResult result = serverDriver.modify(vendor.getUuid(), null, model);
                    if (result.isFailed()) {
                        return result;
                    }
                    CloudServer vm =
                        JSONObject.parseObject(JSONObject.toJSONString(result.getData()), CloudServer.class);
                    server.setCpu(vm.getCpu());
                    server.setMemory(vm.getMemory());
                    server.setDisk(vm.getDisk());
                    server.setGmtModify(new Date());
                    // 配置升级的时候 才修改uuid为虚拟机对应的订单sn
                    if (alteration.getOperation().equals(AlterationParam.Operation.Upgrade)) {
                        server.setUuid(alteration.getNewInstance());
                    }
                    if (null != alteration.getUpgradeSkuId()) {
                        server.setSkuId(alteration.getUpgradeSkuId());
                    }
                    cloudServerRepository.update(server);
                    volumes = volumeRepository.listByServerId(server.getId());
                    Map<String, Volume> oldMap = Maps.newHashMap();
                    for (Volume disk : volumes) {
                        oldMap.put(disk.getVolumeUuid(), disk);
                    }
                    List<Volume> newDiskDevices = vm.getDiskDevices();
                    // 新增的磁盘
                    List<Volume> addDiskDevices = new ArrayList<>();
                    // 新增磁盘设置uuid
                    if (AlterationParam.Operation.AddDisk == alteration.getOperation()) {
                        List<ElementModel> upgrade = alteration.getUpgrade();
                        for (Volume newDiskDevice : newDiskDevices) {
                            if (!oldMap.containsKey(newDiskDevice.getVolumeUuid())) {
                                addDiskDevices.add(newDiskDevice);
                            } else {
                                Volume volume = oldMap.get(newDiskDevice.getVolumeUuid());
                                if (!volume.getName().equals(newDiskDevice.getName())) {
                                    volume.setName(newDiskDevice.getName());
                                    volumeRepository.update(volume);
                                }
                            }
                        }
                        logger.info("add disk device size：{}", addDiskDevices.size());
                        logger.info("add disk element size：{}", upgrade.size());
                        if (addDiskDevices.size() == upgrade.size()) {
                            for (int i = 0; i < upgrade.size(); i++) {
                                ElementModel elementModel = upgrade.get(i);
                                String uuid = elementModel.getUuid();
                                String category = elementModel.getCategory();
                                elementModel.getSkuId();
                                addDiskDevices.get(i).setUuid(uuid);
                                addDiskDevices.get(i).setCategory(category);
                                addDiskDevices.get(i).setSkuId(elementModel.getSkuId());
                            }
                        }
                        List<Volume> newAddDisks = new ArrayList<>();
                        for (Volume disk : addDiskDevices) {
                            disk.preSave(context.getTarget(), context.getTarget(), 0L, server.getVendorId());
                            disk.setServerId(server.getId());
                            disk.setCatalog(context.getCatalog());
                            disk.setExpiredTime(server.getExpiredTime());
                            volumeRepository.save(disk);
                            OrderMessage message = new OrderMessage(disk.getUuid(), Operation.Upgrade,
                                OrderItemStatus.ChangeSuccess, null, "云主机升级成功", disk.getGmtModify(),
                                disk.getExpiredTime(), null, ResourceCategory.Computer.name(), context);
                            message.setNewSn(disk.getUuid());
                            amqpTemplate.convertAndSend("resource.result.queue", message);
                            newAddDisks.add(disk);
                        }
                        Map<Long, Volume> usedVolumeMap = new HashMap<>();
                        if (!ListTool.isEmpty(addDataDisks)) {
                            for (JSONObject addDataDisk : addDataDisks) {
                                if (addDataDisk.containsKey("createLvm") && addDataDisk.getBoolean("createLvm")
                                    && !StringUtils.isEmpty(addDataDisk.getString("device"))) {
                                    String device = addDataDisk.getString("device");
                                    Volume existVolume = volumeRepository.getByLvmMntp(server.getId(), device);
                                    Volume findVolume = null;
                                    for (Volume newAddDisk : newAddDisks) {
                                        if (addDataDisk.getInteger("disk").intValue() == newAddDisk.getSize().intValue()
                                            && !usedVolumeMap.containsKey(newAddDisk.getId())) {
                                            usedVolumeMap.put(newAddDisk.getId(), newAddDisk);
                                            findVolume = newAddDisk;
                                            break;
                                        }
                                    }
                                    BocloudResult lvmResult = null;
                                    if (null != existVolume) {
                                        findVolume.setFileSystem(existVolume.getFileSystem());
                                        lvmResult = lvmService.lvmExtend(server, vendor, addDataDisk, findVolume, context);
                                    } else {
                                        lvmResult = lvmService.lvmCreate(server, vendor, addDataDisk, findVolume, context);
                                    }
                                    //如果lvm挂载失败，调用worker删除
                                    if (lvmResult.isFailed()) {
//                                        List<String> diskUUids = new ArrayList<>();
//                                        List<String> diskNames = new ArrayList<>();
//                                        for (Volume newAddDisk : newAddDisks) {
//                                            diskUUids.add(newAddDisk.getVolumeUuid());
//                                            diskNames.add(newAddDisk.getName());
//                                        }
//                                        deleteDisk(context, server, vendor, diskUUids,diskNames);
                                        //逻辑修改，如果挂载LVM失败，磁盘不需要删除，但需要在站内信中给出明确说明
                                        throw new Exception("lvm挂载失败，原因："+lvmResult.getMessage());
                                    }
                                }
                            }
                        }
                    } else {
                        SyncVmwareUtils utils = new SyncVmwareUtils(cloudServerRepository, dataStoreRepository,
                            serverRepository, snapshotRepository, networkRepository, clusterRepository,
                            storeHostRepository, networkCardRepository, portGroupRepository, networkHostRepository,
                            serverConfigRepository, resourceRepository, ipRepository, imageRepository,
                            volumeRepository);
                        List<DataStore> stores = dataStoreRepository.listByVendor(vendor.getId());
                        Map<String, DataStore> storeMap = new HashMap<>();
                        stores.forEach(s -> storeMap.put(s.getStoreVal(), s));
                        utils.syncDiskDevice(storeMap, volumes, newDiskDevices, server.getVdcId(), vendor.getId(),
                            server.getId(), context.getTarget());
                        // 处理lvm
                        List<JSONObject> editDataDisks = alteration.getEditDataDisks();
                        List<ElementModel> upgrade = alteration.getUpgrade();
                        if (!ListTool.isEmpty(editDataDisks)) {
                            for (JSONObject editDataDisk : editDataDisks) {
                                Volume findVolume =
                                    volumeRepository.getDiskByName(server.getId(), editDataDisk.getString("name"));
                                Assert.notNull(findVolume, "硬盘不存在");
                                // 编辑
                                if(!ListTool.isEmpty(upgrade) && null != upgrade.get(0).getSkuId()) {
                                	findVolume.setSkuId(upgrade.get(0).getSkuId());
                                	volumeRepository.update(findVolume);
                                }
                                BocloudResult lvmResult = null;
                                if (!StringUtils.isEmpty(findVolume.getLvmMntp())) {
                                    findVolume.setFileSystem(findVolume.getFileSystem());
                                    lvmResult = lvmService.lvmResize(server, vendor, editDataDisk, findVolume, context);
                                    //如果lvm挂载失败，由于vc不提供缩盘，所以不做任何操作
                                } else {
                                    String device = editDataDisk.getString("device");
                                    if (StringUtils.isEmpty(device)) {
                                        continue;
                                    }
                                    Volume existVolume = volumeRepository.getByLvmMntp(server.getId(), device);
                                    if (null != existVolume) {
                                        findVolume.setFileSystem(existVolume.getFileSystem());
                                        lvmResult = lvmService.lvmExtend(server, vendor, editDataDisk, findVolume, context);
                                    } else {
                                        lvmResult = lvmService.lvmCreate(server, vendor, editDataDisk, findVolume, context);
                                    }
                                    List<String> diskNames = Lists.newArrayList(findVolume.getName());
                                    List<String> diskUuids = Lists.newArrayList(findVolume.getVolumeUuid());
                                    //如果lvm挂载失败，调用worker删除
                                    if (lvmResult.isFailed()) {
//                                        deleteDisk(context, server, vendor,diskUuids, diskNames);
                                        //逻辑修改，如果挂载LVM失败，磁盘不需要删除，但需要在站内信中给出明确说明
                                        throw new Exception("lvm挂载失败，原因："+lvmResult.getMessage());
                                    }
                                }
                            }
                        }
                    }
                    break;
                case TENCENT:
                case ALIYUN:
                case HUAWEI:
                case TCE:
                case AWS:
                case QCLOUD:
                	JSONObject pubCloudOjbect = new JSONObject();
                	pubCloudOjbect.put("id", server.getId());
                	pubCloudOjbect.put(Common.VENDORID, server.getVendorId());
                	pubCloudOjbect.put("flavorId", alteration.getFlavorId());
                	BocloudResult bocloudResult = this.resize(pubCloudOjbect.toJSONString(), context);
                	if(bocloudResult.isFailed()) {
                		throw new RuntimeException(bocloudResult.getMessage());
                	}
                	break;
                default:
                    return new BocloudResult<>(false, "暂不支持");
            }
            List<CmdbInfo> infos = Lists.newArrayList();
            infos.add(CmdbInfoConvertor.getInfo(server, "modify", null));
            cmdbMessagePublisher.send(CmdbInfoConvertor.getModel(BoCloudService.IMS, infos));
            OrderMessage message = new OrderMessage(alteration.getInstance(), Operation.Upgrade,
                OrderItemStatus.ChangeSuccess, null, "云主机配置修改成功", server.getGmtModify(), server.getExpiredTime(), null,
                ResourceCategory.Computer.name(), context);
            message.setNewSn(alteration.getNewInstance());
            amqpTemplate.convertAndSend("resource.result.queue", message);
            return new BocloudResult<>(true, "升级成功");
        } catch (Exception e) {
            logger.error("Get error message：{}", e);
            return new BocloudResult<>(false, e.getMessage());
        }
    }

    /** @Author: lxy
     * @Description: 取资源池非禁用状态下存储
     * @Date 2021/7/2 11:46
     * @Param server
     * @param storageHostMap
     * @return java.lang.Long
     * @throws:
     **/
    private Long getaStoreId(CloudServer server, Map<Long, StoreHost> storageHostMap) throws Exception {
        List<PoolGroupRelation> poolGroupRelations = new ArrayList<>();
        List<Long> storeEnable = new ArrayList<>();
        //说明是自服务申请
        if (null != server.getPoolGroupId()) {
            //首选查询资源池中设置禁用的资源
            poolGroupRelations = poolGroupRelationRepository.listByGroupId(server.getPoolGroupId());
            if (!ListTool.isEmpty(poolGroupRelations)) {
                storeEnable = poolGroupRelations.stream().filter(poolGroupRelation -> storageHostMap.containsKey(poolGroupRelation.getTarget())).filter(poolGroupRelation -> !poolGroupRelation.getEnabled()).map(PoolGroupRelation::getTarget).collect(Collectors.toList());
                storeEnable.stream().forEach(
                        store -> {
                            storageHostMap.remove(store);
                        }
                );
            }
        }
        if (storageHostMap.isEmpty()) {
            throw new Exception("没有可用存储资源，请联系管理员！");
        }
        int rn = new Random().nextInt(storageHostMap.size());
        int k = 0;
        Long storeId = null;
        for (Long key : storageHostMap.keySet()) {
            if(k==rn){
                storeId = key;
                continue;
            }
            k++;
        }
        if (storeId == null) {
            throw new Exception("没有找到可用存储资源，请联系管理员！");
        }
        return storeId;
    }

    /** @Author: lxy
     * @Description: 删除磁盘
     * @Date 2021/7/1 15:12
     * @Param context
     * @param server
     * @param vendor
     * @param diskUUids
     * @param diskNames
     * @return void
     * @throws:
     **/
    private void deleteDisk(RequestContext context, CloudServer server, CloudVendor vendor, List<String> diskUUids,List<String> diskNames) {
        //卸载lvm
        BocloudResult result = deleteLvmDisk(diskUUids, server, vendor, context);
        if (result.isFailed()&&!result.getMessage().contains("There was a problem while connecting")) {
            Assert.isTrue(result.isSuccess(), result.getMessage());
        }
        //删除物理盘
        result = serverDriver.deleteDisk(vendor.getUuid(), server.getInstanceId(), diskUUids);
        Assert.isTrue(result.isSuccess(), result.getMessage());
        List<Volume> volumes = volumeRepository.listByNames(server.getId(), diskNames);
        Integer disk = 0;
        for (Volume volume : volumes) {
            disk += null == volume.getSize() ? 0 : volume.getSize();
            volumeRepository.remove(volume.getId(), context.getTarget());
        }
        Integer oldDisk = null == server.getDisk() ? 0 : server.getDisk();
        server.setDisk(oldDisk - disk < 0 ? 0 : oldDisk - disk);
        server.setGmtModify(new Date());
        cloudServerRepository.update(server);
    }

    /** @Author: lxy
     * @Description: 如果存在lvm挂载，需要先卸载
     * @Date 2021/6/25 18:26
     * @Param diskNames
     * @param server
     * @param vendor
     * @param context
     * @return com.bocloud.common.model.BocloudResult
     * @throws:
     **/
    private BocloudResult deleteLvmDisk(List<String> diskUUids,CloudServer server,CloudVendor vendor, RequestContext context) {
        //查询需要卸载lvm的磁盘uuid
        BocloudResult selectDiskUuid = serverDriver.selectDiskUuid(vendor.getUuid(), server.getInstanceId(), diskUUids);
        Assert.isTrue(selectDiskUuid.isSuccess(), selectDiskUuid.getMessage());
        List<String> spaceIds =
                JSONArray.parseArray(JSONObject.toJSONString(selectDiskUuid.getData()), String.class);
        //调用lvm卸载
        BocloudResult lvmDelete  = lvmService.lvmDelete(server, vendor, spaceIds, context);
        if (lvmDelete.isFailed()) {
            if (lvmDelete.getMessage().contains("There was a problem while connecting")) {
                return lvmDelete;
            }else {
                Assert.isTrue(lvmDelete.isSuccess(), lvmDelete.getMessage());
            }
        }
        List<JSONObject> lvmResult = JSONArray.parseArray(JSONObject.toJSONString(lvmDelete.getData()), JSONObject.class);
        //lvm卸载失败的磁盘id
        List<String> delSpecIds = new ArrayList<>();
        if (!ListTool.isEmpty(lvmResult)) {
            for (JSONObject lvm:lvmResult) {
                String scsiId = lvm.get("scsiId").toString();
                if (spaceIds.contains(scsiId)) {
                    delSpecIds.add(scsiId);
                }
            }
        }
        if (ListTool.isEmpty(delSpecIds)) {
            return new BocloudResult<>(true, "lvm删除成功");
        }else {
            return new BocloudResult<>(false, "lvm删除失败，请重新操作，id值为：" + JSONObject.toJSON(delSpecIds));
        }
    }

    /**
     * 公有云自服务虚机变更
     * @param params
     * @param context
     * @return
     */
	public BocloudResult resize(String params, RequestContext context) {
		JSONObject object = JSONTools.isJSONObj(params);
		if (null == object) {
			return new BocloudResult<>(false, "参数格式错误");
		}
		// 虚拟机ID
		Long id = object.getLong(Common.ID);
		// 云平台ID
		Long vendorId = object.getLong(Common.VENDORID);
		// 规格ID
		Long flavorId = object.getLong("flavorId");
		Boolean forceStop = object.getBoolean("forceStop") == null ? false : object.getBoolean("forceStop");
		String path = CloudServer.class.getSimpleName() + "_" + id;
		try (BocloudACLock lock = lockFactory.getACLock(path)) {
			Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
			// 云供应商
			CloudVendor vendor = cloudVendorRepository.query(vendorId);
			Optional.ofNullable(vendor).orElseThrow(() -> new Exception("云平台不存在"));
			// 虚拟机
			CloudServer server = cloudServerRepository.query(id);
			Optional.ofNullable(server).orElseThrow(() -> new Exception("虚拟机不存在"));
			String serverStatus = server.getStatus();
			if (!forceStop) {
				if ("RUNNING".equalsIgnoreCase(server.getStatus())) {
					return new BocloudResult<>(false, "配置调整需要在关机状态下操作!");
				}
			}
			// 规格
			Flavor finalFlavor = flavorRepository.query(flavorId);
			Optional.ofNullable(finalFlavor).orElseThrow(() -> new Exception("规格不存在"));

			if (CloudProvider.HUAWEI.name().equals(vendor.getType())
					|| CloudProvider.FUSIONCLOUD.name().equals(vendor.getType())
					|| CloudProvider.MANAGEONE.name().equals(vendor.getType())
					|| CloudProvider.QCLOUD.name().equals(vendor.getType())
					|| CloudProvider.PQCLOUD.name().equals(vendor.getType())
					|| CloudProvider.TCE.name().equals(vendor.getType())
					|| CloudProvider.AZURE.name().equals(vendor.getType())
					|| CloudProvider.AWS.name().equals(vendor.getType())
					|| CloudProvider.ALIYUN.name().equals(vendor.getType())
					|| CloudProvider.TENCENT.name().equals(vendor.getType())) {
				// 支持 高配 --> 低配 所以不做判断处理
			} else {
				// 新配置的CPU，磁盘，内存不能小于原配置
				if (finalFlavor.getCpu() < server.getCpu() || finalFlavor.getDisk() < server.getDisk()
						|| (finalFlavor.getMemory().compareTo(server.getMemory()) < 0)) {
					return new BocloudResult<>(false, "CPU、磁盘和内存大小不能小于原配置");
				}
			}
			try {
				// 修改配置
				BocloudResult result = new BocloudResult<>();
				if (CloudProvider.TENCENT.name().equals(vendor.getType())
						|| CloudProvider.TCE.name().equals(vendor.getType())) {
					result = serverDriver.resize(server.getInstanceId(), finalFlavor.getFlavorUuid(), forceStop,
							vendor.getUuid(), server.getRegionId());
				} else {
					result = serverDriver.resize(server.getInstanceId(), finalFlavor.getFlavorUuid(), vendor.getUuid(),
							server.getRegionId());
				}
				if (result.isSuccess()) {
					// 更新配置
					ServerModel model = serverOperationHelper.parseObject(result.getData(), ServerModel.class);
					if (model.getStatus().equals(BocloudStatus.Server.ERROR.name())) {
						server.setStatus(BocloudStatus.Server.EXCEPTION.name());
					} else {
						server.setStatus(model.getStatus());
					}
					server.setCpu(finalFlavor.getCpu());
					server.setMemory(finalFlavor.getMemory());
					server.setFlavorName(finalFlavor.getName());
					server.setFlavorUuid(finalFlavor.getFlavorUuid());
					cloudServerRepository.update(server);
				} else {
					server.setStatus(serverStatus);
					cloudServerRepository.update(server);
				}
				ResourceEvent event = new ResourceEvent(server.getId(), "规格变更", result.isSuccess() ? "成功" : "失败",
						context.getTarget(), new Date(), "VM", vendor.getId(), context.getCatalog());
				resourceEventRepository.save(event);
			} catch (Exception e) {
				server.setStatus(serverStatus);
				cloudServerRepository.update(server);
				logger.error("cloudServer resize error:", e);
			}
			return new BocloudResult<>(true, "规格变更成功");
		} catch (Exception e) {
			logger.error("CloudServer resize error:", e);
			return new BocloudResult<>(false, "修改配置失败 :" + e.getMessage());
		}
	}

    @Override
    public BocloudResult upgradeConfig(String params, RequestContext context) {
        logger.info("变更参数：" + params);
        JSONObject jsonObject = JSONObject.parseObject(params);
        if (null == jsonObject) {
            logger.error("Incorrect parameter format");
            return new BocloudResult<>(false, "参数格式错误");
        }
        // 虚拟机ID
        Long id = jsonObject.getLong("id");
        // CPU
        Integer cpu = jsonObject.getInteger("cpu");
        // 内存
        BigDecimal memory = jsonObject.getBigDecimal("memory");
        // 磁盘
        Integer systemDisk = jsonObject.getInteger("systemDisk");
        // 数据盘
        Integer dataDisk = jsonObject.getInteger("dataDisk");
        try {
            CloudServer server = cloudServerRepository.get(id);
            Optional.ofNullable(server).orElseThrow(() -> new Exception("虚拟机不存在"));
            CloudVendor vendor = cloudVendorRepository.query(server.getVendorId());
            Optional.ofNullable(vendor).orElseThrow(() -> new Exception("云平台不存在"));
            ServerModel model = new ServerModel();
            model.setCpu(cpu);
            model.setMemory(memory);
            model.setInstanceId(server.getInstanceId());
            model.setName(server.getName());
            model.setSystemDiskSize(systemDisk);
            model.setDataDisk(dataDisk);
            Vdc vdc = vdcRepository.query(server.getVdcId());
            Optional.ofNullable(vdc).orElseThrow(() -> new Exception("数据中心不存在"));
            model.setVdcName(vdc.getName());
            Server host = serverRepository.query(server.getHostId());
            Optional.ofNullable(host).orElseThrow(() -> new Exception("虚拟机所属主机不存在"));
            List<StoreHost> storeHosts = storeHostRepository.list(host.getId(), "PM");
            if (ListTool.isEmpty(storeHosts)) {
                return new BocloudResult<>(false, "该虚拟机所属宿主机未绑定任何存储");
            }
            Long storeId = storeHosts.get(new Random().nextInt(storeHosts.size())).getStoreId();
            DataStore datastore = dataStoreRepository.query(storeId);
            model.setDatastore(datastore.getName());
            BocloudResult result = serverDriver.modify(vendor.getUuid(), null, model);
            if (result.isFailed()) {
                return result;
            }
            CloudServer vm = JSONObject.parseObject(JSONObject.toJSONString(result.getData()), CloudServer.class);
            server.setCpu(vm.getCpu());
            server.setMemory(vm.getMemory());
            server.setDisk(vm.getDisk());
            server.setGmtModify(new Date());
            cloudServerRepository.update(server);
            SyncVmwareUtils utils = new SyncVmwareUtils(cloudServerRepository, dataStoreRepository, serverRepository,
                snapshotRepository, networkRepository, clusterRepository, storeHostRepository, networkCardRepository,
                portGroupRepository, networkHostRepository, serverConfigRepository, resourceRepository, ipRepository,
                imageRepository, volumeRepository);
            List<Volume> volumes = volumeRepository.listByServerId(server.getId());
            List<DataStore> stores = dataStoreRepository.listByVendor(vendor.getId());
            Map<String, DataStore> storeMap = new HashMap<>();
            stores.forEach(s -> storeMap.put(s.getStoreVal(), s));
            utils.syncDiskDevice(storeMap, volumes, vm.getDiskDevices(), server.getVdcId(), vendor.getId(),
                server.getId(), context.getTarget());
            List<CmdbInfo> infos = Lists.newArrayList();
            infos.add(CmdbInfoConvertor.getInfo(server, "modify", null));
            cmdbMessagePublisher.send(CmdbInfoConvertor.getModel(BoCloudService.IMS, infos));
            if (null != dataDisk && 0L != dataDisk) {
                JSONObject object = new JSONObject();
                object.put("pasd", server.receivePswd());
                if ("LINUX".equalsIgnoreCase(server.getOsCategory())) {
                    object.put("host", server.getManagerIp());
                    object.put("category", "Linux");
                    object.put("device", "/dev/sdb");
                } else {
                    String managerIp = null;
                    String privateIps = server.getPrivateIps();
                    if (!StringUtils.isEmpty(privateIps)) {
                        List<JSONObject> objects = JSONArray.parseArray(privateIps, JSONObject.class);
                        for (JSONObject privateIp : objects) {
                            String networkName = privateIp.getString("networkName");
                            if (!StringUtils.isEmpty(networkName) && networkName.contains("mngt-paas")) {
                                managerIp = privateIp.getString("address");
                                break;
                            }
                        }
                    }
                    if (StringUtils.isEmpty(managerIp)) {
                        managerIp = server.getManagerIp();
                    }
                    object.put("host", managerIp);
                    object.put("category", "Windows");
                }
                this.formatDisk(server.getId(), object, context);
            }
            return new BocloudResult<>(true, "升级配置成功");
        } catch (Exception e) {
            logger.error("Get error message：", e);
            return new BocloudResult<>(false, "升级配置失败");
        }
    }

    @Override
    public BocloudResult extension(ExtensionParam param) {
        try {
            CloudServer server = cloudServerRepository.getByUuid(param.getInstance());
            Optional.ofNullable(server).orElseThrow(() -> new Exception("虚拟机不存在"));

            Calendar calendar = Calendar.getInstance();
            calendar.setTime(server.getExpiredTime());
            calendar.add(Calendar.MONTH, param.getExtension());
            server.setExpiredTime(calendar.getTime());
            cloudServerRepository.update(server);

            OrderMessage message = new OrderMessage(param.getInstance(), Operation.Extension,
                OrderItemStatus.ExtensionSuccess, param.getExtension(), "云主机延期成功", null, calendar.getTime(), null,
                ResourceCategory.Computer.name(), param.getContext());
            amqpTemplate.convertAndSend("resource.result.queue", message);
            return new BocloudResult<>(true, "云主机延期成功");
        } catch (Exception e) {
            logger.error("postpone cms fail:", e);
            return new BocloudResult<>(false, "云主机延期失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult cancelation(CancelationParam param) {
        CloudServer server = null;
        try {
            server = cloudServerRepository.getByUuid(param.getInstance());
            Optional.ofNullable(server).orElseThrow(() -> new Exception("云主机不存在"));
        } catch (Exception e) {
            logger.error("Get error message：{}", e.getMessage());
            return new BocloudResult<>(false, e.getMessage());
        }
        RequestContext context = param.getContext();
        String path = CloudServer.class.getSimpleName() + "_" + server.getId();
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            CloudVendor vendor = cloudVendorRepository.query(server.getVendorId());
            Optional.ofNullable(vendor).orElseThrow(() -> new Exception("云平台不存在"));
            CloudProvider provider = CloudProvider.valueOf(vendor.getType());
            List<Volume> dataVolumes = null;
            switch (provider) {
                case VMWARE:
                    dataVolumes = volumeRepository.listByServerId(server.getId(), server.getVendorId(), false);
                    break;
                default:
                    dataVolumes = volumeRepository.listByServerId(server.getId(), server.getVendorId(), true);
                    break;
            }

            BocloudResult result =
                serverDriver.remove(server.getInstanceId(), server.getName(), vendor.getUuid(), server.getRegionId());
            if (result.isFailed()) {
                return result;
            }
            result = serverOperationHelper.remove(server.getId(), null, vendor, server, null, context,
                param.getIsDeletePublicIp());
            if (result.isFailed()) {
                return result;
            }
            OrderMessage message =
                new OrderMessage(param.getInstance(), Operation.Cancelation, OrderItemStatus.UnsubscribeSuccess, null,
                    result.getMessage(), null, null, null, ResourceCategory.Computer.name(), context);
            List<QuotaBean> quotas = new ArrayList<>();
            quotas.add(new QuotaBean("compute." + vendor.getType().toLowerCase() + ".server", 1));
            quotas.add(new QuotaBean("meta.cpu", server.getCpu()));
            quotas.add(new QuotaBean("meta.mem", server.getMemory().intValue()));
            quotas.add(new QuotaBean("meta.disk", server.getDisk()));
            message.setQuotas(quotas);
            message.setCategory(ResourceCategory.Computer.name());
            amqpTemplate.convertAndSend("resource.result.queue", message);
            if (!ListTool.isEmpty(dataVolumes)) {
                OrderMessage volumeOrderMessage =
                    new OrderMessage(null, Operation.Cancelation, OrderItemStatus.UnsubscribeSuccess, null, "云硬盘退订成功",
                        null, null, new ArrayList<>(), ResourceCategory.Storage.name(), context);
                volumeOrderMessage.setCategory(ResourceCategory.Storage.name());
                for (Volume volume : dataVolumes) {
                    volumeOrderMessage.setSn(volume.getUuid());
                    List<QuotaBean> volumeQuotas = new ArrayList<>();
                    volumeQuotas.add(new QuotaBean(vendor.getType().toLowerCase() + ".standard.volume", 1));
                    volumeQuotas.add(new QuotaBean("meta.disk", volume.getSize()));
                    volumeOrderMessage.setQuotas(volumeQuotas);
                    amqpTemplate.convertAndSend("resource.result.queue", volumeOrderMessage);
                }
            }
            // 清空回收站
            cosInternalService.recycle(server.getUuid());
            return new BocloudResult<>(true, "云主机退订成功");
        } catch (Exception e) {
            logger.error("Get error message：{}", e.getMessage());
            return new BocloudResult<>(false, "云主机退订失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult formatDisk(Long id, JSONObject object, RequestContext context) {
        try {
            CloudServer server = null;
            if (null == id) {
                server = cloudServerRepository.getByInstanceId(object.getString("instanceId"));
            } else {
                server = cloudServerRepository.query(id);
            }
            Optional.ofNullable(server).orElseThrow(() -> new Exception("虚拟机不存在"));
            CloudVendor vendor = cloudVendorRepository.query(server.getVendorId());
            Optional.ofNullable(vendor).orElseThrow(() -> new Exception("云平台不存在"));
            String host = object.getString("host");
            String category = object.getString("category");
            String pasd = object.getString("pasd");
            Map<String, Object> params = new HashMap<>();
            List<Map<String, Object>> targets = new ArrayList<>();
            Map<String, Object> target = new HashMap<>();
            target.put("host", host);
            Encryptor encryptor = new AESEncrptor();
            target.put("pasd", encryptor.encrypt(pasd, null));
            Map<String, Object> module = new HashMap<>();
            if ("Linux".equalsIgnoreCase(category)) {
                target.put("user", "root");
                target.put("category", "Linux");
                target.put("port", 22);
                Map<String, Object> args = new HashMap<>();
                args.put("device", object.getString("device"));
                module.put("args", args);
                module.put("name", "resizefs");
                Map<String, Object> options = new HashMap<>();
                options.put("become", true);
                module.put("options", options);
                params.put("timeout", 1800);
            } else if ("Windows".equalsIgnoreCase(category)) {
                target.put("category", "Windows");
                target.put("user", "administrator");
                target.put("port", 5986);
                target.put("rawName", host);
                Map<String, Object> winDisk = new HashMap<>();
                winDisk.put("driver", "E");
                winDisk.put("disk_number", 1);
                Map<String, Object> args = new HashMap<>();
                args.put("win_disk", winDisk);
                module.put("args", args);
                module.put("name", "resizefs_windows");
                params.put("timeout", 1800);
            }
            targets.add(target);
            params.put("targets", targets);
            params.put("module", module);
            params.put("response", "async");
            BocloudResult result = diskFormatService.format(vendor, server, params, context);
            if (result.isFailed()) {
                return result;
            }
            return new BocloudResult<>(true, "格式化磁盘任务已下发，请耐心等待执行结果...");
        } catch (Exception e) {
            logger.info("Get error message：{}", e.getMessage());
            return new BocloudResult<>(false, "格式化磁盘任务下发失败");
        }
    }

    @Override
    public BocloudResult createServer(JSONObject param, RequestContext context, String queue) {
        try {
            // 位置
            JSONObject location = param.getJSONObject("location");
            // 配置信息
            JSONObject configs = param.getJSONObject("configs");
            // 资源归属信息
            configs.put("poolGroupId", location.getLong("poolGroupId"));
            configs.put("businessId", location.getLong("businessId"));
            configs.put("projectId", location.getLong("projectId"));
            configs.put("creatorId", location.getLong("creatorId"));
            configs.put("ownerId", location.getLong("ownerId"));
            configs.put("menderId", location.getLong("menderId"));
            String password = configs.getString("password");
            if (!StringUtils.isEmpty(password)) {
                Encryptor encryptor = new AESEncrptor();
                try {
                    password = encryptor.decrypt(password.trim(), null);
                    configs.put("password", password);
                } catch (Exception e) {
                    logger.error("Get error message:{}", e);
                    return new BocloudResult<>(false, e.getMessage());
                }
            }
            configs.put("networks", param.get("networks"));
            configs.put("groups", param.get("groups"));
            CloudVendor vendor = cloudVendorRepository.query(location.getLong("vendorId"));
            Assert.notNull(vendor, "当前可用域未绑定云平台");
            CloudProvider provider = CloudProvider.valueOf(vendor.getType());
            Map<Long, List<Ip>> networkConfigs = new HashMap<>();
            // 网卡端口组关联集合
            Map<Long, Long> portGroupConfigs = new HashMap<>();
            // 通过调度策略分配的宿主机和存储
            String nsxNetworkName = null;
            List<JSONObject> targetObjs = new ArrayList<>();
            if (CloudProvider.VMWARE == provider) {
                Long imageId = configs.getLong("imageId");
                if (null != imageId) {
                    Image targetImage = imageRepository.query(imageId);
                    Assert.notNull(targetImage, "未找到合适的镜像");
                    CloudServer template = cloudServerRepository.query(targetImage.getTemplateId());
                    Assert.notNull(template, "未找到合适的虚拟机模板");
                    configs.put("templateId", targetImage.getTemplateId());
                }
                Map<String, Object> assignMap = Maps.newHashMap();
                assignMap.put("Cpu", configs.getLong("cpu"));
                assignMap.put("Memory", configs.getBigDecimal("memory"));
                assignMap.put("Disk", configs.getLong("disk"));
                assignMap.put("Instance", 1);
                // 根据计算资源池获取可分配宿主机，存储
                BocloudResult<List<JSONObject>> BocloudResult = resSchedulerEngine
                    .selectHost(location.getLong("poolGroupId"), "Cpu", assignMap, configs.getString("diskCategory"));
                Assert.isTrue(BocloudResult.isSuccess(), BocloudResult.getMessage());
                targetObjs = BocloudResult.getData();
                // 判断vcenter是否使用nsx网络
                Long vpcId = configs.getLong("vpcId");
                if (null != vpcId) {

                } else {
                    JSONArray ipConfigs = configs.getJSONArray("networkCardConfigs");
                    for (int j = 0; j < ipConfigs.size(); j++) {
                        IpPool ipPool = null;
                        JSONObject config = ipConfigs.getJSONObject(j);
                        Long poolId = config.getLong("ipPoolId");
                        Long networkCardId = config.getLong("networkCardId");
                        Long portGroupId = config.getLong("portGroupId");
                        portGroupConfigs.put(networkCardId, portGroupId);
                        if (null != poolId && 0L != poolId) {
                            ipPool = ipPoolRepository.query(poolId);
                            Assert.notNull(ipPool, "IP池不存在");
                        }
                        String ipPolicy = config.getString("ipPolicy");
                        if (StringUtils.isEmpty(ipPolicy)) {
                            ipPolicy = "Auto";
                        }
                        switch (config.getString("ipPolicy")) {
                            case "Dhcp":
                                BocloudResult<List<Ip>> dhcpIpResult =
                                    ipService.achieveDhcpIps(poolId, 1L, ipPool.getVersion());
                                Assert.isTrue(dhcpIpResult.isSuccess(), dhcpIpResult.getMessage());
                                List<Ip> dhcpIps = dhcpIpResult.getData();
                                networkConfigs.put(networkCardId, dhcpIps);
                                break;
                            case "Auto":
                                BocloudResult<List<Ip>> autoIpData =
                                    ipService.achievePoolIps(poolId, 1L, ipPool.getVersion());
                                Assert.isTrue(autoIpData.isSuccess(), autoIpData.getMessage());
                                List<Ip> autoIps = autoIpData.getData();
                                networkConfigs.put(networkCardId, autoIps);
                                break;
                            case "Manual":
                                List<String> addresses = JSONArray
                                    .parseArray(JSONObject.toJSONString(config.getJSONArray("address")), String.class);
                                List<Ip> manualIps = ipRepository.listIpsByPool(poolId, addresses);
                                Assert.notEmpty(manualIps, "未设置正确的IP地址");
                                networkConfigs.put(networkCardId, manualIps);
                                break;
                            default:
                                break;
                        }
                    }
                }
            }
            // 数据预处理
            JSONObject newObj = configs;
            newObj.put("name", configs.getString("name") + "_" + IDFactory.instance().mac());
            if (!ListTool.isEmpty(targetObjs)) {
                JSONObject targetObj = targetObjs.get(0);
                newObj.put("storeId", targetObj.getLong("storeId"));
                newObj.put("hostId", targetObj.getLong("hostId"));
                // 数据盘分配存储
                if (newObj.containsKey("addDiskList")) {
                    List<JSONObject> addDiskList =
                        JSONArray.parseArray(newObj.getString("addDiskList"), JSONObject.class);
                    if (!ListTool.isEmpty(addDiskList)) {
                        List<String> dataStoreNames =
                            resSchedulerEngine.assignStore(targetObj.getLong("hostId"), addDiskList);
                        if (ListTool.isEmpty(dataStoreNames)) {
                            return new BocloudResult<>(false, "为虚拟机分配数据盘存储发生错误");
                        }
                        newObj.put("dataStoreNames", dataStoreNames);
                        List<Integer> disks = new ArrayList<>();
                        for (JSONObject dataDisk : addDiskList) {
                            Integer disk = dataDisk.getInteger("disk");
                            disks.add(disk);
                        }
                        newObj.put("disks", disks);
                    }
                    newObj.put("dataDiskList", newObj.getString("addDiskList"));
                    newObj.remove("addDiskList");
                }
            }
            BocloudResult<ServerBuilder> builderResult = serverOperationHelper.getProcess(provider, vendor, context);
            Assert.isTrue(builderResult.isSuccess(), builderResult.getMessage());
            ServerBuilder process = builderResult.getData();
            BocloudResult<ProcessResult> result = null;
            if (CloudProvider.VMWARE == provider) {
                Map<Long, Ip> ipMap = new HashMap<>();
                for (Map.Entry<Long, List<Ip>> entry : networkConfigs.entrySet()) {
                    Long networkCardId = entry.getKey();
                    List<Ip> ips = entry.getValue();
                    Ip ip = ips.get(0);
                    ipMap.put(networkCardId, ip);
                }
                result = serverOperationHelper.prepareVcenter(newObj, context, vendor, process, ipMap, portGroupConfigs,
                    nsxNetworkName);
            } else {
                result = serverOperationHelper.prepare(
                    JSONObject.parseObject(newObj.toJSONString(), VmGenericParam.class), context, vendor, process);
            }
            Assert.isTrue(result.isSuccess(), result.getMessage());
            result.getData().setServerBuilder(process);
            ProcessResult processResult = result.getData();
            // 启动一个线程从MQ上获取数据
            new Thread(() -> serverOperationHelper.builder(vendor.getType(), vendor.getId(),
                processResult.getCloudServer(), context, process, queue)).start();
            return new BocloudResult<>(true, "申请任务已经下发，正在执行……");
        } catch (Exception e) {
            logger.error("Apply virtual machine error", e);
            return new BocloudResult<>(false, "申请虚拟机失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult recycle(String uuid, RequestContext context) {
        String path = CloudServer.class.getSimpleName() + "_" + uuid;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            CloudServer server = cloudServerRepository.getByUuid(uuid);
            Optional.ofNullable(server).orElseThrow(() -> new Exception("虚拟机不存在"));
            CloudVendor vendor = cloudVendorRepository.query(server.getVendorId());
            Optional.ofNullable(vendor).orElseThrow(() -> new Exception("云平台不存在"));
            Long id = server.getId();
            cloudServerRepository.recycle(id, context.getTarget());
            taskExecutor.execute(() -> {
                // 关机
                if (!BocloudStatus.Server.STOPPED.name().equalsIgnoreCase(server.getStatus())) {
                    BocloudResult result = cloudServerService.stop(id, context);
                    if (result.isSuccess()) {
                        // 等待关机成功，否则有些云平台的会删除不了
                        try {
                            waitTask(id);
                        } catch (Exception e) {
                            logger.error("Get error message:{}", e);
                        }
                    } else {
                        server.setRecycle(false);
                        cloudServerRepository.update(server);
                    }
                }
                // 回收站生成记录
                String spec = server.getCpu() + "核/" + server.getMemory() + "GB/" + server.getDisk() + "GB";
                Recycled recycled = new Recycled(server.getName(), server.getUuid(),
                    ResourceCategory.Computer.name() + "-" + server.getVendorType(), server.getId(),
                    server.getProjectId(), server.getCatalog().name(), spec);
                recycled.setTenantId(server.getTenantId());
                recycled.setUserId(server.getOwnerId());
                recycled.setProjectId(server.getProjectId());
                recycled.setMenderId(server.getMenderId());
                recycled.setOwnerId(server.getOwnerId());
                logger.info("ims发送 recycled 数据到cos：{}", JSONObject.toJSON(recycled));
                BocloudResult joinRecycle = cosInternalService.joinRecycle(recycled);
                logger.info("生成回收站记录结果：{}", JSONObject.toJSON(joinRecycle));
                RequestContext requestContext = new RequestContext(server.getCatalog(), server.getTenantId(),
                    server.getCreatorId(), server.getProjectId(), null);
                // 发送站内信
                NotifyMessage notifyMessage = new NotifyMessage(requestContext, "虚拟机放入回收站通知",
                    "虚拟机【" + server.getName() + "】已关机放入回收站", true, false);
                amqpTemplate.convertAndSend("event.notice.queue", notifyMessage);
                String operate = vendor.getType().toLowerCase() + ".vm";
                OperateResult message = new OperateResult(true, "虚拟机【" + server.getName() + "】已放入回收站", operate,
                    MapTools.simpleMap(Common.VENDORID, vendor.getId()), OperateCategory.ResourceEvent, context);
                resourceEventPublisher.send(message);
            });
            return new BocloudResult<>(true, "虚拟机【" + server.getName() + "】加入回收站任务已下发，请耐心等待结果...");
        } catch (Exception e) {
            logger.error("虚拟机加入回收站失败:", e);
            return new BocloudResult<>(false, "虚拟机加入回收站失败：" + e.getMessage());
        }

    }

    @Override
    public BocloudResult batchRecycle(String param, RequestContext context) {
        try {
            JSONObject batchParams = JSON.parseObject(param, JSONObject.class);
            List<String> resourceUuidArray = JSON.parseArray(batchParams.getString("resourceUuids"), String.class);
            if (ListTool.isEmpty(resourceUuidArray)) {
                return new BocloudResult<>(false, "参数格式错误！");
            }
            for (String uuid : resourceUuidArray) {
                this.recycle(uuid, context);
            }
            return new BocloudResult<>(true, "批量移入回收站任务已下发，正在执行...");
        } catch (Exception e) {
            logger.error("批量加入回收站异常：" + e.getMessage());
            return new BocloudResult<>(false, "批量加入回收站异常：" + e.getMessage());
        }
    }

}