package com.bocloud.ims.service.builder;

import java.io.File;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

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.driver.network.PortDriver;
import com.bocloud.cmp.driver.storage.StorageDriver;
import com.bocloud.cmp.driver.storage.VolumeDriver;
import com.bocloud.cmp.driver.storage.VolumePoolDriver;
import com.bocloud.cmp.model.NetworkBean;
import com.bocloud.cmp.model.NetworkModel;
import com.bocloud.cmp.model.ServerModel;
import com.bocloud.cmp.model.VolumeModel;
import com.bocloud.cmp.provider.utils.IPAddress;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.RequestContext;
import com.bocloud.ims.entity.resource.CloudServer;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.Cluster;
import com.bocloud.ims.entity.resource.Flavor;
import com.bocloud.ims.entity.resource.FlavorExtraSpecs;
import com.bocloud.ims.entity.resource.Image;
import com.bocloud.ims.entity.resource.Ip;
import com.bocloud.ims.entity.resource.Network;
import com.bocloud.ims.entity.resource.Port;
import com.bocloud.ims.entity.resource.PortFixedIp;
import com.bocloud.ims.entity.resource.Server;
import com.bocloud.ims.entity.resource.ServerConfig;
import com.bocloud.ims.entity.resource.Subnet;
import com.bocloud.ims.entity.resource.Volume;
import com.bocloud.ims.entity.resource.VolumePool;
import com.bocloud.ims.entity.resource.VolumeTemplate;
import com.bocloud.ims.repository.resource.CloudServerRepository;
import com.bocloud.ims.repository.resource.ClusterRepository;
import com.bocloud.ims.repository.resource.FlavorExtraSpecsRepository;
import com.bocloud.ims.repository.resource.FlavorRepository;
import com.bocloud.ims.repository.resource.ImageRepository;
import com.bocloud.ims.repository.resource.ImageVolumeRepository;
import com.bocloud.ims.repository.resource.IpPoolRepository;
import com.bocloud.ims.repository.resource.IpRepository;
import com.bocloud.ims.repository.resource.NetworkRepository;
import com.bocloud.ims.repository.resource.PortFixedIpRepository;
import com.bocloud.ims.repository.resource.PortRepository;
import com.bocloud.ims.repository.resource.ServerConfigRepository;
import com.bocloud.ims.repository.resource.ServerRepository;
import com.bocloud.ims.repository.resource.StorageRepository;
import com.bocloud.ims.repository.resource.SubnetRepository;
import com.bocloud.ims.repository.resource.VolumePoolRepository;
import com.bocloud.ims.repository.resource.VolumeRepository;
import com.bocloud.ims.repository.resource.VolumeTemplateRepository;
import com.bocloud.ims.service.transporter.vendor.PowervcTransporter;

/**
 * Powervc
 *
 * @author luyanchao
 * @since 2019/1/28 17:44
 */
public class PowervcServerBuilder implements ServerBuilder {

	private final ThreadPoolTaskExecutor taskExecutor;

	private final Environment environment;

	private final ImageRepository imageRepository;
	private final ImageVolumeRepository imageVolumeRepository;
	private final FlavorRepository flavorRepository;
	private final FlavorExtraSpecsRepository flavorExtraSpecsRepository;
	private final NetworkRepository networkRepository;
	private final SubnetRepository subnetRepository;
	private final ServerRepository serverRepository;
	private final ServerConfigRepository serverConfigRepository;
	private final CloudServerRepository cloudServerRepository;
	private final StorageRepository storageRepository;
	private final VolumeRepository volumeRepository;
	private final VolumeTemplateRepository volumeTemplateRepository;
	private final VolumePoolRepository volumePoolRepository;
	private final ClusterRepository clusterRepository;
	private final PortRepository portRepository;
	private final PortFixedIpRepository portFixedIpRepository;
	private final IpPoolRepository ipPoolRepository;
	private final IpRepository ipRepository;

	private final PowervcTransporter powervcTransportor;

	private final ServerDriver serverDriver;
	private final StorageDriver storageDriver;
	private final VolumeDriver volumeDriver;
	private final VolumePoolDriver volumePoolDriver;
	private final PortDriver portDriver;
	private final RequestContext context;
	private final CloudVendor vendor;
	private ServerModel serverModel;

	public PowervcServerBuilder(ThreadPoolTaskExecutor taskExecutor, Environment environment,
			ImageRepository imageRepository, ImageVolumeRepository imageVolumeRepository,
			FlavorRepository flavorRepository, NetworkRepository networkRepository, SubnetRepository subnetRepository,
			ServerRepository serverRepository, ServerConfigRepository serverConfigRepository,
			CloudServerRepository cloudServerRepository, StorageRepository storageRepository,
			VolumeRepository volumeRepository, FlavorExtraSpecsRepository flavorExtraSpecsRepository,
			VolumeTemplateRepository volumeTemplateRepository, VolumePoolRepository volumePoolRepository,
			ClusterRepository clusterRepository, PortRepository portRepository,
			PortFixedIpRepository portFixedIpRepository, IpPoolRepository ipPoolRepository, IpRepository ipRepository,
			PowervcTransporter powervcTransportor, ServerDriver serverDriver, StorageDriver storageDriver,
			VolumeDriver volumeDriver, VolumePoolDriver volumePoolDriver, PortDriver portDriver, RequestContext context,
			CloudVendor vendor) {
		this.taskExecutor = taskExecutor;
		this.environment = environment;
		this.imageRepository = imageRepository;
		this.imageVolumeRepository = imageVolumeRepository;
		this.flavorRepository = flavorRepository;
		this.networkRepository = networkRepository;
		this.subnetRepository = subnetRepository;
		this.serverRepository = serverRepository;
		this.serverConfigRepository = serverConfigRepository;
		this.cloudServerRepository = cloudServerRepository;
		this.storageRepository = storageRepository;
		this.volumeRepository = volumeRepository;
		this.flavorExtraSpecsRepository = flavorExtraSpecsRepository;
		this.volumeTemplateRepository = volumeTemplateRepository;
		this.volumePoolRepository = volumePoolRepository;
		this.clusterRepository = clusterRepository;
		this.portRepository = portRepository;
		this.portFixedIpRepository = portFixedIpRepository;
		this.ipPoolRepository = ipPoolRepository;
		this.ipRepository = ipRepository;
		this.powervcTransportor = powervcTransportor;
		this.serverDriver = serverDriver;
		this.storageDriver = storageDriver;
		this.volumeDriver = volumeDriver;
		this.volumePoolDriver = volumePoolDriver;
		this.portDriver = portDriver;
		this.context = context;
		this.vendor = vendor;
	}

	@Override
	public BocloudResult<ServerModel> prepare(JSONObject object) throws Exception {
		int count = object.getIntValue("count");

		serverModel = new ServerModel();
		// 处理基本信息
		serverModel.setName(object.getString("name"));
		serverModel.setPassword(object.getString("password"));
		serverModel.setRemark(object.getString("remark"));
		// 处理规格信息
		long flavorId = object.getLongValue("flavorId");
		Flavor flavor = flavorRepository.query(flavorId);
		FlavorExtraSpecs extraSpecs = null;
		if (flavor == null) {
			return new BocloudResult<>(false, "未找到规格");
		} else if (null != flavor.getExtraSpecsId()) {
			// 获取额外配置
			extraSpecs = flavorExtraSpecsRepository.query(flavor.getExtraSpecsId());
			if (extraSpecs == null) {
				return new BocloudResult<>(false, "未找到规格扩展信息");
			}
		}
		if (object.get("flavor") != null) {
			JSONObject flavorDefine = object.getJSONObject("flavor");
			flavor.setCpu(flavorDefine.getInteger("cpu"));
			flavor.setMemory(flavorDefine.getBigDecimal("memory"));
			if (flavorDefine.get("hmcCpu") != null) {
				extraSpecs.setProcUnits(flavorDefine.getDoubleValue("hmcCpu"));
			}
			if (extraSpecs.getProcUnits() == null) {
				extraSpecs.setProcUnits(0.5);
			}
		}
		// 判断规格范围
		if ((extraSpecs.getMinProcUnits() != null && extraSpecs.getProcUnits() < extraSpecs.getMinProcUnits())
				|| (extraSpecs.getMaxProcUnits() != null && extraSpecs.getProcUnits() > extraSpecs.getMaxProcUnits())) {
			return new BocloudResult<>(false,
					"处理器单元数必须在该计算模板已定义的最大值和最小值之间：" + extraSpecs.getMinProcUnits() + "-" + extraSpecs.getMaxProcUnits());
		}
		if ((extraSpecs.getMinVcpu() != null && flavor.getCpu() < extraSpecs.getMinVcpu())
				|| (extraSpecs.getMaxVcpu() != null && flavor.getCpu() > extraSpecs.getMaxVcpu())) {
			return new BocloudResult<>(false,
					"处理器核数必须在该计算模板已定义的最大值和最小值之间：" + extraSpecs.getMinVcpu() + "-" + extraSpecs.getMaxVcpu());
		}
		if ((extraSpecs.getMinMem() != null && flavor.getMemory().compareTo(extraSpecs.getMinMem()) < 0)
				|| (extraSpecs.getMaxMem() != null && flavor.getMemory().compareTo(extraSpecs.getMaxMem()) > 0)) {
			return new BocloudResult<>(false,
					"内存大小必须在该计算模板已定义的最大值和最小值之间：" + extraSpecs.getMinMem() + "-" + extraSpecs.getMaxMem());
		}
		if (flavor.getMemory().multiply(new BigDecimal(1024)).intValue() % 64 != 0) {
			return new BocloudResult<>(false, "内存大小需要是64MB的整数倍");
		}
		// 判断规格中的cpu设置是否合规
		if (flavor.getCpu() / extraSpecs.getProcUnits() > 10 || flavor.getCpu() / extraSpecs.getProcUnits() < 1) {
			return new BocloudResult<>(false, "处理器核数和处理单元数的比值需在1-10之间");
		}
		serverModel.setFlavorUuid(flavor.getFlavorUuid());
		serverModel.setMemory(flavor.getMemory());
		serverModel.setCpu(flavor.getCpu());
		serverModel.setHmcCpu(extraSpecs.getProcUnits());
		// 支持建立分区时指定主机
		Long serverId = object.getLong("serverId");
		if (serverId != null) {
			Server server = serverRepository.query(serverId);
			if (server == null) {
				return new BocloudResult<>(false, "未找到宿主机");
			}
			serverModel.setHostName(server.getHostname());
			// 判断主机资源是否满足规格要求
			ServerConfig serverConfig = serverConfigRepository.getBySid(serverId);
			if (serverConfig == null) {
				return new BocloudResult<>(false, "未找到宿主机配置");
			}
			double needCpuUnit = extraSpecs.getProcUnits() * count;
			double freeCpuUnit = serverConfig.getHmcCpu() - serverConfig.getHmcCpuReserved()
					- serverConfig.getHmcCpuUsed();
			if (needCpuUnit > freeCpuUnit) {
				return new BocloudResult<>(false,
						String.format("cpu资源不足，创建该云主机需要%.2f个CPU单元，所选主机剩余%.2f个CPU单元", needCpuUnit, freeCpuUnit));
			}
			double needMemory = flavor.getMemory().multiply(new BigDecimal(count)).doubleValue();
			double freeMemory = serverConfig.getMemoryCapacity() - serverConfig.getMemReserved()
					- serverConfig.getMemUsed();
			if (needMemory > freeMemory) {
				return new BocloudResult<>(false,
						String.format("内存资源不足，创建该云主机需要%.4fGB内存，所选主机剩余%.4fGB内存", needMemory, freeMemory));
			}
		}
		// 支持主机组
		Long clusterId = object.getLong("clusterId");
		if (clusterId != null) {
			Cluster cluster = clusterRepository.query(clusterId);
			if (cluster == null) {
				return new BocloudResult<>(false, "未找到主机组");
			}
			serverModel.setClusterUuid(cluster.getUuid());
			// 判断主机组的资源是否满足规格要求
			List<Server> servers = serverRepository.listByCluster(clusterId);
			long validateServerCount = 0;
			for (Server server : servers) {
				// 判断主机资源是否满足规格要求
				ServerConfig serverConfig = serverConfigRepository.getBySid(server.getId());
				if (serverConfig == null) {
					return new BocloudResult<>(false, "未找到宿主机配置");
				}
				long validateCpuUnitCnt = Math.round(Math.floor(
						(serverConfig.getHmcCpu() - serverConfig.getHmcCpuReserved() - serverConfig.getHmcCpuUsed())
								/ extraSpecs.getProcUnits()));
				long validateMemoryCnt = Math.round(Math.floor(
						(serverConfig.getMemoryCapacity() - serverConfig.getMemReserved() - serverConfig.getMemUsed())
								/ flavor.getMemory().longValue()));
				validateServerCount += Math.min(validateCpuUnitCnt, validateMemoryCnt);
			}
			if (validateServerCount < count) {
				return new BocloudResult<>(false,
						count == 1 ? "主机组资源不足" : "主机组资源不足，按照当前配置该主机组只能满足" + validateServerCount + "个云主机的创建");
			}
		}
		// 检测主机和主机组必须有其中一个有值
		if (serverId == null && clusterId == null) {
			return new BocloudResult<>(false, "部署目标主机/主机组不能为空");
		}
		// 处理镜像信息
		long imageId = object.getLongValue("imageId");
		Image image = imageRepository.query(imageId);
		if (image == null) {
			return new BocloudResult<>(false, "未找到映像");
		}
		serverModel.setImageUuid(image.getImageUuid());
		// 处理卷
		List<VolumeModel> disks = new ArrayList<>();
		Map<Long, Double> poolMap = new HashMap<>();
		// 处理镜像卷
		List<Volume> imageVolumes = object.getJSONArray("imageVolumes").toJavaList(Volume.class);
		for (int i = 0; i < imageVolumes.size(); i++) {
			Volume volume = volumeRepository.query(imageVolumes.get(i).getId());
			if (volume == null) {
				return new BocloudResult<>(false, "未找到存储卷");
			}
			if ("error".equals(volume.getStatus())) {
				return new BocloudResult<>(false, "无法部署映像,所选映像的卷[" + volume.getName() + "]的状态为错误");
			}
			if (imageVolumes.get(i).getTemplateId() == null) {
				return new BocloudResult<>(false, "映像卷：" + volume.getName() + "未选择存储器模板");
			}
			VolumeTemplate template = volumeTemplateRepository.get(imageVolumes.get(i).getTemplateId());
			if (template == null) {
				return new BocloudResult<>(false, "未找到存储器模板");
			}

			VolumeModel disk = new VolumeModel();
			disk.setImageVolume(true);
			disk.setBootIndex(i);
			disk.setVolumeUuid(volume.getVolumeUuid());
			disk.setVolumeTemplateUuid(template.getUuid());
			disk.setDeleteWithInstance(true);
			disks.add(disk);

			// 计算每个实例的映像卷需要的存储池容量
			double realSize = volume.getSize()
					* (template.getCapacityPercent() == null || template.getCapacityPercent() < 0 ? 1
							: template.getCapacityPercent() / 100);
			if (template.getPoolId() == null) {
				return new BocloudResult<>(false, "未找到存储器模板[" + template.getName() + "]使用的存储池");
			}
			VolumePool basePool = volumePoolRepository.get(template.getPoolId());
			if (basePool == null) {
				return new BocloudResult<>(false, "未找到存储器模板[" + template.getName() + "]使用的存储池");
			}
			poolMap.merge(basePool.getId(), realSize, (a, b) -> a + b);
			if (template.getCopyPoolId() != null) {
				VolumePool copyPool = volumePoolRepository.get(template.getCopyPoolId());
				if (copyPool == null) {
					return new BocloudResult<>(false, "未找到存储器模板[" + template.getName() + "]使用的存储池");
				}
				poolMap.merge(copyPool.getId(), realSize, (a, b) -> a + b);
			}
		}
		// 处理其他存储卷
		if (object.get("otherVolumes") != null) {
			List<Volume> volumes = object.getJSONArray("otherVolumes").toJavaList(Volume.class);
			for (int i = 0; i < volumes.size(); i++) {
				Volume volume = volumes.get(i);
				if (volume.getId() != null) {
					Volume volumeFromDB = volumeRepository.query(volume.getId());
					if (volumeFromDB == null) {
						return new BocloudResult<>(false, "未找到存储卷");
					}
					if (count > 1 && !volumeFromDB.getMultiattach()) {
						return new BocloudResult<>(false, "创建多个云主机实例时，不能添加非共享的存储卷");
					}
					VolumeModel disk = new VolumeModel();
					disk.setBootVolume(volume.getBootVolume());
					disk.setImageVolume(false);
					disk.setBootIndex(imageVolumes.size() + i);
					disk.setVolumeUuid(volumeFromDB.getVolumeUuid());
					disk.setDeleteWithInstance(false);
					disks.add(disk);
				} else {
					VolumeModel disk = new VolumeModel();
					disk.setBootVolume(volume.getBootVolume());
					disk.setImageVolume(false);
					disk.setBootIndex(imageVolumes.size() + i);
					disk.setName(volume.getName());
					disk.setSize(volume.getSize());
					disk.setRemark(volume.getRemark());
					disk.setMultiattach(volume.getMultiattach());
					VolumeTemplate volumeTemplate = volumeTemplateRepository.get(volume.getTemplateId());
					if (volumeTemplate == null) {
						return new BocloudResult<>(false, "未找到存储器模板");
					}
					disk.setVolumeTemplateUuid(volumeTemplate.getUuid());
					disk.setDeleteWithInstance(true);
					disks.add(disk);

					// 计算每个实例的新增卷需要的存储池容量
					double realSize = volume.getSize()
							* (volumeTemplate.getCapacityPercent() < 0 ? 1 : volumeTemplate.getCapacityPercent() / 100);
					if (volumeTemplate.getPoolId() == null) {
						return new BocloudResult<>(false, "未找到存储器模板[" + volumeTemplate.getName() + "]使用的存储池");
					}
					VolumePool basePool = volumePoolRepository.get(volumeTemplate.getPoolId());
					if (basePool == null) {
						return new BocloudResult<>(false, "未找到存储器模板[" + volumeTemplate.getName() + "]使用的存储池");
					}
					poolMap.merge(basePool.getId(), realSize, (a, b) -> a + b);
					if (volumeTemplate.getCopyPoolId() != null) {
						VolumePool copyPool = volumePoolRepository.get(volumeTemplate.getCopyPoolId());
						if (copyPool == null) {
							return new BocloudResult<>(false, "未找到存储器模板[" + volumeTemplate.getName() + "]使用的存储池");
						}
						poolMap.merge(copyPool.getId(), realSize, (a, b) -> a + b);
					}
				}
			}
		}
		serverModel.setDiskDevices(disks);
		// 判断存储池容量是否充足
		for (Map.Entry<Long, Double> poolSize : poolMap.entrySet()) {
			VolumePool pool = volumePoolRepository.get(poolSize.getKey());
			if (pool == null) {
				return new BocloudResult<>(false, "未找到存储池");
			}
			if (pool.getFreeCapacity() < poolSize.getValue() * count) {
				return new BocloudResult<>(false, "存储空间不足，" + "存储池[" + pool.getName() + "]剩余空间："
						+ pool.getFreeCapacity() + "GB，" + "创建该云主机需要空间：" + poolSize.getValue() * count + "GB");
			}
		}
		// 处理网络
		List<NetworkBean> networkBeans = object.getJSONArray("networks").toJavaList(NetworkBean.class);
		List<NetworkModel> networkModels = new ArrayList<>();
		for (NetworkBean networkBean : networkBeans) {
			NetworkModel networkModel = new NetworkModel();

			Network network = networkRepository.query(networkBean.getNetworkId());
			if (network == null) {
				return new BocloudResult<>(false, "未找到网络");
			}
			networkModel.setNetworkUuid(network.getNetworkUuid());
			List<Subnet> subnets = subnetRepository.listByNetwork(network.getId());
			if (StringUtils.isNotEmpty(networkBean.getFixIp())) {
				if (count > 1) {
					return new BocloudResult<>(false, "创建多个云主机实例时，不能指定网络IP地址");
				}
				// 判断ip对否在网络内
				Subnet subnetOfIp = null;
				for (Subnet subnet : subnets) {
					List<String> ipPools = JSON.parseArray(subnet.getIpPools(), String.class);
					IPAddress ipAddress = IPAddress.getIPAddress(networkBean.getFixIp());
					if (ipAddress.isInPools(networkBean.getFixIp(), ipPools)) {
						subnetOfIp = subnet;
						break;
					}
				}
				if (subnetOfIp == null) {
					return new BocloudResult<>(false, "IP地址不在网络范围内");
				}
				Ip ip = ipRepository.checkExist(networkBean.getFixIp(), subnetOfIp.getId(), vendor.getId());
				if (ip != null) {
					return new BocloudResult<>(false, "IP地址已经被占用");
				}
				networkModel.setFixedIp(networkBean.getFixIp());
			} else {
				// 如果不是dhcp网络，则判断当前网络的可用ip是否满足实例数量
				if (subnets != null && subnets.size() > 0) {
					long allIpCnt = 0;
					long usedIpCnt = 0;
					IPAddress ipAddress = IPAddress.get("v4");
					for (Subnet subnet : subnets) {
						JSONArray ipPools = JSON.parseArray(subnet.getIpPools());
						for (int i = 0; i < ipPools.size(); i++) {
							String ipPool = ipPools.getString(i);
							long ipStart = ipAddress.ipToInteger(ipPool.split("-")[0]).longValue();
							long ipEnd = ipAddress.ipToInteger(ipPool.split("-")[1]).longValue();
							allIpCnt += ipEnd - ipStart + 1;
						}
					}
					List<Port> ports = portRepository.listAllByNetworkId(network.getId());
					for (Port port : ports) {
						List<PortFixedIp> portFixedIps = portFixedIpRepository.listByPortId(port.getId());
						usedIpCnt += portFixedIps.size();
					}
					if (allIpCnt - usedIpCnt < count) {
						return new BocloudResult<>(false, "网络：" + network.getName() + "的可用IP地址不足，该网络剩余可用IP数量为"
								+ (allIpCnt - usedIpCnt) + "个，创建该云主机需要" + count + "个可用IP");
					}
				}
			}
			networkModels.add(networkModel);
		}
		serverModel.setNetworks(networkModels);
		// 活时输入文本或选择文件
		String activeCmd = object.get("activeInput") == null ? "" : object.getString("activeInput");
		String activeFile = object.getString("activeFile");
		if (StringUtils.isNotEmpty(activeFile)) {
			String nfsPath = environment.getProperty("upload.storage.path");
			if (StringUtils.isEmpty(nfsPath)) {
				return new BocloudResult<>(false, "未设定nfs路径");
			}
			File file = new File(nfsPath + activeFile);
			if (!file.exists()) {
				return new BocloudResult<>(false, "未找到文件：" + file.getName());
			}
			activeCmd += FileUtils.readFileToString(file, "utf-8");
		}
		if (StringUtils.isNotEmpty(activeCmd)) {
			serverModel.setActiveCmd(Base64.getEncoder().encodeToString(activeCmd.getBytes("utf-8")));
		}
		return new BocloudResult<>(true, serverModel, "执行成功");
	}

	@Override
	public BocloudResult<CloudServer> builder(CloudServer server) throws Exception {
		Logger logger = LoggerFactory.getLogger(PowervcServerBuilder.class);
		BocloudResult bocloudResult;
		// 执行创建
		bocloudResult = serverDriver.create(vendor.getUuid(), null, serverModel);
		serverModel = (ServerModel) bocloudResult.getData();
		// 如果创建失败，这里返回的serverModel可能为空
		if (serverModel != null) {
			String instanceId = serverModel.getInstanceId();
			if (StringUtils.isEmpty(instanceId)) {
				return new BocloudResult<>(false, "返回的instanceId为空");
			}
			// 将instanceId更新数据库数据
			server.setInstanceId(serverModel.getInstanceId());
			cloudServerRepository.update(server);
			// 同步该云主机的全部信息
			server = powervcTransportor.syncCloudServer(vendor, serverModel.getInstanceId(), context.getTarget());
		}
		if (bocloudResult.isFailed()) {
			return new BocloudResult<>(false, bocloudResult.getMessage());
		}
		final long hostId = server.getHostId();
		taskExecutor.submit(() -> {
			long start = System.currentTimeMillis();
			int failedCnt = 0;
			while (System.currentTimeMillis() - start < 5 * 60 * 1000) {
				try {
					if (failedCnt >= 10) {
						logger.error("延迟更新云主机[" + serverModel.getName() + "]信息失败：出现异常次数大于10次");
						break;
					}
					logger.info("正在延迟更新云主机[" + serverModel.getName() + "]信息，3秒后重试...");
					Thread.sleep(3000);
					BocloudResult getServerResult = serverDriver.detail(serverModel.getInstanceId(), vendor.getUuid(),
							null);
					if (getServerResult.isFailed()) {
						failedCnt++;
						logger.warn("延迟更新云主机[" + serverModel.getName() + "]信息失败：", getServerResult.getMessage());
						continue;
					}
					ServerModel getServerModel = (ServerModel) getServerResult.getData();
					if (getServerModel == null) {
						failedCnt++;
						logger.warn("延迟更新云主机[" + serverModel.getName() + "]信息失败： 未查询到云主机信息");
						continue;
					}
					int completedCnt = 0;
					if (getServerModel.getOsName() != null) {
						logger.debug(
								"延迟更新云主机[" + serverModel.getName() + "]操作系统信息，操作系统为：" + getServerModel.getOsName());
						CloudServer cloudServer = cloudServerRepository.getByInstanceId(serverModel.getInstanceId(),
								vendor.getId());
						cloudServer.setOsName(getServerModel.getOsName());
						cloudServerRepository.update(cloudServer);
						// 如果当前操作系统是Unknown，则有可能稍后还会有变化，所以暂时不退出延迟更新
						if (!"Unknown".equals(getServerModel.getOsName())) {
							completedCnt++;
						}
					}
					if (getServerModel.getCpu() != null && getServerModel.getCpu() > 0) {
						logger.debug("延迟更新云主机[" + serverModel.getName() + "]CPU信息，CPU个数为：" + getServerModel.getCpu());
						CloudServer cloudServer = cloudServerRepository.getByInstanceId(serverModel.getInstanceId(),
								vendor.getId());
						cloudServer.setCpu(getServerModel.getCpu());
						cloudServerRepository.update(cloudServer);
						completedCnt++;
					}
					if (getServerModel.getHmcCpu() != null && getServerModel.getHmcCpu() > 0) {
						logger.debug(
								"延迟更新云主机[" + serverModel.getName() + "]CPU单元信息，CPU单元为：" + getServerModel.getHmcCpu());
						CloudServer cloudServer = cloudServerRepository.getByInstanceId(serverModel.getInstanceId(),
								vendor.getId());
						cloudServer.setHmcCpu(getServerModel.getHmcCpu());
						cloudServerRepository.update(cloudServer);

						ServerConfig hostConfig = serverConfigRepository.getBySid(hostId);
						if (hostConfig != null) {
							hostConfig.setHmcCpuUsed(hostConfig.getHmcCpuUsed() + serverModel.getHmcCpu());
							serverConfigRepository.update(hostConfig);
						}

						completedCnt++;
					}
					if (getServerModel.getMemory() != null && getServerModel.getMemory().doubleValue() > 0) {
						logger.debug("延迟更新云主机[" + serverModel.getName() + "]内存信息，内存为：" + getServerModel.getMemory());
						CloudServer cloudServer = cloudServerRepository.getByInstanceId(serverModel.getInstanceId(),
								vendor.getId());
						cloudServer.setMemory(getServerModel.getMemory());
						cloudServerRepository.update(cloudServer);

						ServerConfig hostConfig = serverConfigRepository.getBySid(hostId);
						if (hostConfig != null) {
							hostConfig.setMemUsed(hostConfig.getMemUsed() + serverModel.getMemory().doubleValue());
							serverConfigRepository.update(hostConfig);
						}

						completedCnt++;
					}
					if (completedCnt >= 4) {
						break;
					}
				} catch (Exception e) {
					failedCnt++;
					logger.warn("延迟更新云主机[" + serverModel.getName() + "]信息失败：", e);
					continue;
				}
			}
			logger.info("延迟更新云主机[" + serverModel.getName() + "]结束");
		});
		return new BocloudResult<>(true, server, "执行成功");
	}
}
