package com.bocloud.ims.service.builder;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.compute.ServerDriver;
import com.bocloud.cmp.driver.network.GwQosDriver;
import com.bocloud.cmp.entity.enums.BocloudStatus;
import com.bocloud.cmp.entity.enums.ResourceCategory;
import com.bocloud.cmp.model.AddressBean;
import com.bocloud.cmp.model.NetworkBean;
import com.bocloud.cmp.model.PortFixedIpModel;
import com.bocloud.cmp.model.PortModel;
import com.bocloud.cmp.model.ServerModel;
import com.bocloud.cmp.model.ServerVolumeModel;
import com.bocloud.cmp.model.VMBean;
import com.bocloud.cmp.provider.utils.IPAddress;
import com.bocloud.common.enums.OSCategory;
import com.bocloud.common.enums.ResourceCatalog;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.RequestContext;
import com.bocloud.common.utils.IDFactory;
import com.bocloud.common.utils.ListTool;
import com.bocloud.ims.entity.resource.CloudServer;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.Flavor;
import com.bocloud.ims.entity.resource.Image;
import com.bocloud.ims.entity.resource.Ip;
import com.bocloud.ims.entity.resource.Ip.IpStatus;
import com.bocloud.ims.entity.resource.IpPool;
import com.bocloud.ims.entity.resource.Keypair;
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.QosPolicy;
import com.bocloud.ims.entity.resource.Region;
import com.bocloud.ims.entity.resource.Resource;
import com.bocloud.ims.entity.resource.ResourceEvent;
import com.bocloud.ims.entity.resource.SecurityGroup;
import com.bocloud.ims.entity.resource.Server;
import com.bocloud.ims.entity.resource.ServerLabel;
import com.bocloud.ims.entity.resource.ServerSgroup;
import com.bocloud.ims.entity.resource.Snapshot;
import com.bocloud.ims.entity.resource.Subnet;
import com.bocloud.ims.entity.resource.TenantProvider;
import com.bocloud.ims.entity.resource.Volume;
import com.bocloud.ims.interfaces.resource.VendorProjectService;
import com.bocloud.ims.repository.resource.CloudServerRepository;
import com.bocloud.ims.repository.resource.FlavorRepository;
import com.bocloud.ims.repository.resource.ImageRepository;
import com.bocloud.ims.repository.resource.IpPoolRepository;
import com.bocloud.ims.repository.resource.IpRepository;
import com.bocloud.ims.repository.resource.KeypairRepository;
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.QosPolicyRepository;
import com.bocloud.ims.repository.resource.RegionRepository;
import com.bocloud.ims.repository.resource.ResourceEventRepository;
import com.bocloud.ims.repository.resource.ResourceRepository;
import com.bocloud.ims.repository.resource.SecurityGroupRepository;
import com.bocloud.ims.repository.resource.ServerLabelRepository;
import com.bocloud.ims.repository.resource.ServerRepository;
import com.bocloud.ims.repository.resource.ServerSgroupRepository;
import com.bocloud.ims.repository.resource.SnapshotRepository;
import com.bocloud.ims.repository.resource.SubnetRepository;
import com.bocloud.ims.repository.resource.VolumeRepository;
import com.bocloud.ims.service.utils.PwdRandom;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.Date;
import java.util.List;
import java.util.Map;

public class OSServerBuilder implements ServerBuilder {

	private static Logger logger = LoggerFactory.getLogger(OSServerBuilder.class);
	private CloudServerRepository cloudServerRepository;
	private ServerRepository serverRepository;
	private NetworkRepository networkRepository;
	private SubnetRepository subnetRepository;
	private ImageRepository imageRepository;
	private FlavorRepository flavorRepository;
	private VolumeRepository volumeRepository;
	private PortRepository portRepository;
	private PortFixedIpRepository portFixedIpRepository;
	private IpRepository ipRepository;
	private IpPoolRepository ipPoolRepository;
	private ResourceRepository resourceRepository;
	private ResourceEventRepository resourceEventRepository;
	private SecurityGroupRepository securityGroupRepository;
	private ServerSgroupRepository serverSgroupRepository;
	private KeypairRepository keypairRepository;
	private SnapshotRepository snapshotRepository;
	private ServerLabelRepository serverLabelRepository;
	private RegionRepository regionRepository;
	private ServerDriver serverDriver;
	private RequestContext context;
	private CloudVendor vendor;
	private ServerModel model;
	private VendorProjectService vendorProjectService;
	private QosPolicyRepository qosPolicyRepository;

	public OSServerBuilder(CloudServerRepository cloudServerRepository, ServerRepository serverRepository,
			NetworkRepository networkRepository, SubnetRepository subnetRepository, ImageRepository imageRepository,
			VolumeRepository volumeRepository, FlavorRepository flavorRepository, PortRepository portRepository,
			PortFixedIpRepository portFixedIpRepository, IpRepository ipRepository, IpPoolRepository ipPoolRepository,
			ResourceRepository resourceRepository, ResourceEventRepository resourceEventRepository,
			SecurityGroupRepository securityGroupRepository, ServerSgroupRepository serverSgroupRepository,
			KeypairRepository keypairRepository, SnapshotRepository snapshotRepository,
			ServerLabelRepository serverLabelRepository, RegionRepository regionRepository, ServerDriver serverDriver,
			RequestContext context, CloudVendor vendor, GwQosDriver gwQosDriver,
			VendorProjectService vendorProjectService, QosPolicyRepository qosPolicyRepository) {
		super();
		this.qosPolicyRepository = qosPolicyRepository;
		this.cloudServerRepository = cloudServerRepository;
		this.serverRepository = serverRepository;
		this.networkRepository = networkRepository;
		this.subnetRepository = subnetRepository;
		this.imageRepository = imageRepository;
		this.flavorRepository = flavorRepository;
		this.volumeRepository = volumeRepository;
		this.portRepository = portRepository;
		this.portFixedIpRepository = portFixedIpRepository;
		this.ipRepository = ipRepository;
		this.ipPoolRepository = ipPoolRepository;
		this.resourceRepository = resourceRepository;
		this.resourceEventRepository = resourceEventRepository;
		this.securityGroupRepository = securityGroupRepository;
		this.serverSgroupRepository = serverSgroupRepository;
		this.keypairRepository = keypairRepository;
		this.snapshotRepository = snapshotRepository;
		this.serverLabelRepository = serverLabelRepository;
		this.regionRepository = regionRepository;
		this.serverDriver = serverDriver;
		this.context = context;
		this.vendor = vendor;
		this.vendorProjectService = vendorProjectService;
	}

	@Override
	public BocloudResult<ServerModel> prepare(JSONObject object) {
		try {
			String networks = object.getString("networks");// 网络
			String groups = object.getString("groups");// 安全组
			Long imageId = object.getLong("imageId");// 镜像ID
			Long flovorId = object.getLong("flavorId");// 规格ID
			Boolean bootFromVolume = object.getBoolean("bootFromVolume");// 是否从卷启动创建
			String password = object.getString("password");// 密码
			String keypairName = object.getString("keypairName");// 密钥名称
			String name = object.getString("name");// 虚拟机名
			Long sourceValidId = object.getLong("sourceValidId");// 源卷ID
			Long sourceSnapId = object.getLong("sourceSnapId");// 源快照ID
			Long policyId = object.getLong("policyId");// qos policy
			String region = object.getString("region");// 所属域
			if (null == bootFromVolume) {
				bootFromVolume = false;
			}
			model = new ServerModel();
			model.setRegionId(region);
			// 虚拟机标签
			if (!StringUtils.isEmpty(object.getString("labelIds"))) {
				List<Long> labelIds = JSONArray.parseArray(object.getString("labelIds"), Long.class);
				model.setLabelIds(labelIds);
			}
			if (null != policyId) {
				QosPolicy qosPolicy = qosPolicyRepository.query(policyId);
				if (null == qosPolicy) {
					return new BocloudResult<>(false, model, "QoS策略不存在！");
				}
				model.setPolicyUuid(qosPolicy.getPolicyUuid());
			}
			String account = null;
			// 如果未设置密码则随机生成并保存
			if (StringUtils.isEmpty(keypairName) && StringUtils.isEmpty(password)) {
				password = randomStr(10);
			}
			if (null != sourceValidId && 0L != sourceValidId) {
				Volume sourceValid = volumeRepository.query(sourceValidId);
				if (null == sourceValid) {
					return new BocloudResult<>(false, model, "源为卷时已选择的卷不存在");
				}
				model.setSourceValidUuid(sourceValid.getVolumeUuid());
				String imageUuid = sourceValid.getImageUuid();
				if (!StringUtils.isEmpty(imageUuid)) {
					Image image = imageRepository.getByImageUuid(sourceValid.getImageUuid());
					if (null != image) {
						account = image.getDefaultUser();
					}
				}
			}
			if (null != sourceSnapId && 0L != sourceSnapId) {
				Snapshot sourceSnap = snapshotRepository.query(sourceSnapId);
				if (null == sourceSnap) {
					return new BocloudResult<>(false, model, "源为快照时已选择的快照不存在");
				}
				model.setSourceSnapUuid(sourceSnap.getSnapshotUuid());
				Volume sourceValid = volumeRepository.query(sourceSnap.getVolumeId());
				if (null != sourceValid) {
					String imageUuid = sourceValid.getImageUuid();
					if (!StringUtils.isEmpty(imageUuid)) {
						Image image = imageRepository.getByImageUuid(sourceValid.getImageUuid());
						if (null != image) {
							account = image.getDefaultUser();
						}
					}
				}
			}
			if (!StringUtils.isEmpty(keypairName)) {
				// 查询密钥是否存在
				Keypair keypair = keypairRepository.getByName(keypairName, vendor.getId());
				if (null == keypair) {
					return new BocloudResult<>(false, model, "密钥不存在");
				}
			}
			model.setKeypairName(keypairName);
			if (null != imageId && 0L != imageId) {
				// 镜像
				Image image = imageRepository.query(imageId);
				if (null == image) {
					return new BocloudResult<>(false, model, "镜像不存在");
				}
				// 镜像默认用户
				account = image.getDefaultUser();
				String osCategory = image.getOsCategory();
				if ("linux".equalsIgnoreCase(osCategory)) {
					osCategory = OSCategory.LINUX.name();
				} else if ("windows".equalsIgnoreCase(osCategory)) {
					osCategory = OSCategory.WINDOWS.name();
				} else if ("unix".equalsIgnoreCase(osCategory)) {
					osCategory = OSCategory.UNIX.name();
				} else if ("aix".equalsIgnoreCase(osCategory)) {
					osCategory = OSCategory.AIX.name();
				} else {
					osCategory = OSCategory.LINUX.name();
				}
				model.setOsCategory(osCategory);
				model.setOsName(image.getOsName());
				model.setOsVersion(image.getOsVersion());
				if (bootFromVolume) {
					Integer rootSize = object.getInteger("rootSize");// 根磁盘大小
					if (null != image.getMinDisk() && image.getMinDisk() > 0L
							&& rootSize.intValue() < image.getMinDisk().intValue()) {
						return new BocloudResult<>(false, model, "根磁盘大小不能小于镜像最小容量");
					}
					if (rootSize.doubleValue() < image.getSize()) {
						return new BocloudResult<>(false, model, "根磁盘大小不能小于镜像大小");
					}
					model.setRootSize(rootSize);
				}
				model.setBootFromVolume(bootFromVolume);
				model.setImageUuid(image.getImageUuid());
			}
			// 规格
			Flavor flavor = flavorRepository.query(flovorId);
			if (null == flavor) {
				return new BocloudResult<>(false, model, "规格不存在");
			}
			List<NetworkBean> networkBeans = JSONArray.parseArray(networks, NetworkBean.class);
			if (!ListTool.isEmpty(networkBeans)) {
				List<String> ipAddrs = Lists.newArrayList();// 已锁定的IP
				// 校验网络
				for (NetworkBean bean : networkBeans) {
					Network network = networkRepository.query(bean.getNetworkId());
					if (null == network) {
						return new BocloudResult<>(false, model, "网络不存在");
					}
					bean.setNetworkUuid(network.getNetworkUuid());// 设置网络UUID
					bean.setNetworkName(network.getName());
					// 网络下子网IP地址
					List<AddressBean> addresses = bean.getAddresses();
					if (!ListTool.isEmpty(addresses)) {
						for (AddressBean address : addresses) {
							Subnet subnet = subnetRepository.query(address.getSubnetId());
							if (null == subnet) {
								return new BocloudResult<>(false, model, "子网不存在");
							}
							address.setSubnetUuid(subnet.getSubnetUuid());
							address.setSubnetName(subnet.getName());
							address.setNetworkId(network.getId());
							String addr = address.getAddress();
							if (StringUtils.isEmpty(addr)) {
								continue;
							}
							// 判断IP是否存在于指定网络的IP池中
							if (null != addr && !"".equalsIgnoreCase(addr)) {
								Ip ip = ipRepository.checkExist(addr, subnet.getId(), vendor.getId());
								if (null != ip) {
									return new BocloudResult<>(false, model, "指定的IP地址【" + addr + "】已被使用");
								}
								List<String> pools = JSONArray.parseArray(subnet.getIpPools(), String.class);
								if (ListTool.isEmpty(pools)) {
									return new BocloudResult<>(false, model, "该子网IP地址池分配有误");
								}
								IPAddress ipAddress = IPAddress.getIPAddress(addr);
								boolean flag = ipAddress.isInPools(addr, pools);
								if (!flag) {
									return new BocloudResult<>(false, model, "该IP不在该子网的网段内");
								}
								ip = new Ip(addr, ipAddress.getMask(subnet.getCidr()), subnet.getGateway(),
										subnet.getDnsNames(), vendor.getId(), IDFactory.instance().uuid(), null,
										IpStatus.used);
								ip.setCatalog("PORT");
								ip.setNetworkId(subnet.getNetworkId());
								ip.setSubnetId(subnet.getId());
								ipRepository.save(ip);
								ipAddrs.add(address.getSubnetId() + "," + addr);
							}

						}
					}
				}
			}
			model.prepareData(name, account, password, flavor.getFlavorUuid(), networkBeans,
					JSONArray.parseArray(groups, String.class));
		} catch (Exception e) {
			logger.error("Get error Message:", e);
			return new BocloudResult<>(false, model, "fail");
		}
		return new BocloudResult<>(true, model, "success");
	}

	/**
	 * 回收IP
	 *
	 * @param networkBeans
	 * @param vendorId
	 * @return
	 */
	private void recycleIp(List<NetworkBean> networkBeans, Long vendorId) {
		try {
			if (!ListTool.isEmpty(networkBeans)) {
				for (NetworkBean networkBean : networkBeans) {
					List<AddressBean> addresses = networkBean.getAddresses();
					if (ListTool.isEmpty(addresses)) {
						continue;
					}
					for (AddressBean address : addresses) {
						ipRepository.delete(address.getAddress(), address.getSubnetId(), vendor.getId());
					}
				}
			}
		} catch (Exception e) {
			logger.error("recycle ip error:", e);
		}
	}

	@Override
	public BocloudResult<CloudServer> builder(CloudServer cloudServer) {
		// 创建虚拟机
		BocloudResult result = null;
		try {
			// 操作记录
			Long userId = context.getTarget();
			String handler = "虚拟机创建";
			ResourceEvent event = null;
			Resource resource = null;
			// 创建虚拟机
			TenantProvider provider = vendorProjectService.getAncestorProject(vendor.getId(), context.getTenant());
			if (null == provider) {
				result = serverDriver.create(vendor.getUuid(), cloudServer.getOsTenantName(), null, model);
			} else {
				result = serverDriver.create(vendor.getUuid(), provider.getProjectName(), null, model);
			}
			if (result.isSuccess()) {
				event = new ResourceEvent(cloudServer.getId(), handler, "成功", userId, new Date(), "VM", vendor.getId(),
						context.getCatalog());
				String content = JSONObject.toJSONString(result.getData());
				CloudServer server = JSONObject.parseObject(content, CloudServer.class);
				List<Volume> diskDevices = server.getDiskDevices();
				if (!ListTool.isEmpty(diskDevices)) {
					for (Volume volume : diskDevices) {
						List<ServerVolumeModel> models = volume.getModels();
						Map<String, ServerVolumeModel> serverVolumeMap = Maps.newHashMap();
						if (!ListTool.isEmpty(models)) {
							for (ServerVolumeModel model : models) {
								serverVolumeMap.put(model.getInstanceId(), model);
							}
						}
						ServerVolumeModel model = serverVolumeMap.get(server.getInstanceId());
						String device = null;
						if (null != model) {
							device = model.getDevice();
						}
						Volume existVolume = volumeRepository.getByVolumeUuid(volume.getVolumeUuid());
						Long volumeId = null;
						Integer volumeSize = null;
						Region region = regionRepository.getByName(volume.getZone(), vendor.getId());
						if (null != region) {
							volume.setRegion(region.getName());
						}
						if (null == existVolume) {
							volume.setCreatorId(userId);
							volume.setGmtCreate(new Date());
							volume.setVendorId(vendor.getId());
							volume.setDevice(device);
							volume.setServerId(cloudServer.getId());
							volume.setTenantId(context.getTenant());
							volume.setProjectId(context.getProject());
							volumeRepository.save(volume);
							volumeId = volume.getId();
							volumeSize = volume.getSize();
						} else {
							// 更新
							existVolume.setStatus("IN_USE");
							existVolume.setDevice(device);
							existVolume.setGmtModify(new Date());
							existVolume.setMenderId(context.getTarget());
							existVolume.setServerId(cloudServer.getId());
							existVolume.setTenantId(context.getTenant());
							existVolume.setProjectId(context.getProject());
							volumeRepository.update(existVolume);
							volumeId = existVolume.getId();
							volumeSize = existVolume.getSize();
						}
						if ("/dev/vda".equals(device)) {
							cloudServer.setDisk(volumeSize);
							cloudServer.setVolumeId(volumeId);
						}
					}
				} else {
					cloudServer.setDisk(server.getDisk());
				}
				cloudServer.setTenantUuid(server.getTenantUuid());
				cloudServer.setAccount(model.getAccount());
				cloudServer.setPswd(model.getPassword());
				String imageUuid = model.getImageUuid();
				if(!StringUtils.isEmpty(server.getImageUuid())) {
					imageUuid = server.getImageUuid();
				}
				cloudServer.setImageUuid(imageUuid);
				cloudServer.setGroups(server.getGroups());
				cloudServer.setInstanceId(server.getInstanceId());
				cloudServer.setUuid(server.getUuid());
				cloudServer.setMemory(server.getMemory());
				cloudServer.setCpu(server.getCpu());
				cloudServer.setGmtVmCreate(server.getGmtVmCreate());
				Region region = regionRepository.getByName(server.getZone(), vendor.getId());
				if (null != region) {
					cloudServer.setRegion(region.getName());
				}
				String hostName = server.getHostName();
				cloudServer.setHostName(hostName);
				if (null != hostName) {
					Server host = serverRepository.getByName(hostName, vendor.getId());
					if (null != host) {
						cloudServer.setHostId(host.getId());
					}
				}
				cloudServer.setManagerIp(server.getManagerIp());
				String state = server.getStatus();
				logger.info("Start to update vm status...");
				updateStatus(cloudServer, state);
				logger.info("End to update vm status...");
				if (state.equalsIgnoreCase(BocloudStatus.Server.EXCEPTION.name())
						|| state.equalsIgnoreCase(BocloudStatus.Server.SUSPENDED.name())) {
					event = new ResourceEvent(cloudServer.getId(), handler, "失败", userId, new Date(), "VM",
							vendor.getId(), context.getCatalog());
				}
				logger.info("Start to sync vm port...");
				// 电科云 虚拟机IP绑定带宽 2019年11月11日17:36:12
				QosPolicy qosPolicy = new QosPolicy();
				if (null != model.getPolicyUuid()) {
					qosPolicy = qosPolicyRepository.queryByUuid(model.getPolicyUuid(), vendor.getId());
				}
				List<PortModel> ports = server.getPorts();
				// 保存端口
				Map<String, List<PortModel>> portMap = Maps.newHashMap();
				Map<String, NetworkBean> networkMap = Maps.newHashMap();
				Map<String, AddressBean> subnetMap = Maps.newHashMap();
				for (PortModel portModel : ports) {
					Port port = new Port();
					BeanUtils.copyProperties(portModel, port);
					Network network = networkRepository.getByNetId(portModel.getNetworkUuid());
					NetworkBean networkBean = new NetworkBean(network.getId(), network.getName(),
							network.getNetworkUuid());
					networkMap.put(portModel.getNetworkUuid(), networkBean);
					port.preSave(userId, userId, vendor.getId(), network.getId());
					port.setStatus(BocloudStatus.Network.RUNNING.name());
					port.setDeviceOwner("compute:None");
					port.setDeviceUuid(server.getInstanceId());
					port.setQosPolicyUuid(qosPolicy.getPolicyUuid());
					port.setMaxKbps(qosPolicy.getMaxKbps());
					portRepository.save(port);
					// 保存fixedip
					List<PortFixedIpModel> fixedIpModels = portModel.getPortFixedIps();
					if (!ListTool.isEmpty(fixedIpModels)) {
						for (PortFixedIpModel fixedIpModel : fixedIpModels) {
							PortFixedIp portFixedIp = new PortFixedIp();
							BeanUtils.copyProperties(fixedIpModel, portFixedIp);
							portFixedIp.setPortId(port.getId());
							portFixedIp.setPortUuid(portModel.getPortUuid());
							Subnet subnet = subnetRepository.getBySubId(fixedIpModel.getSubnetUuid());
							if (null != subnet) {
								portFixedIp.setSubnetId(subnet.getId());
							}
							portFixedIpRepository.save(portFixedIp);
							AddressBean addressBean = new AddressBean(subnet.getId(), subnet.getName(), network.getId(),
									subnet.getSubnetUuid(), port.getId(), port.getPortUuid(),
									portFixedIp.getIpAddress());
							subnetMap.put(addressBean.getSubnetUuid(), addressBean);
							// 更新IP
							Ip ip = ipRepository.checkExist(fixedIpModel.getIpAddress(), subnet.getId(),
									vendor.getId());
							// IP不存在，则添加IP记录
							if (null == ip) {
								String mask = IPAddress.getIPAddress(fixedIpModel.getIpAddress())
										.getMask(subnet.getCidr());
								ip = new Ip(fixedIpModel.getIpAddress(), mask, subnet.getGateway(),
										subnet.getDnsNames(), vendor.getId(), IDFactory.instance().uuid(), null,
										IpStatus.used);
								ip.setSubnetId(subnet.getId());
								ip.setNetworkId(port.getNetworkId());
								ip.setCatalog("PORT");
								ip.setTarget(port.getId());
								IpPool pool = ipPoolRepository.queryBySubnet(subnet.getId(), vendor.getId());
								if (null != pool) {
									ip.setPoolId(pool.getId());
								}
								ipRepository.save(ip);
							} else {
								ip.setTarget(port.getId());
								ipRepository.update(ip);
							}
						}
					}
					portModel.setPortId(port.getId());
					if (portMap.containsKey(portModel.getNetworkUuid())) {
						List<PortModel> models = portMap.get(portModel.getNetworkUuid());
						models.add(portModel);
					} else {
						List<PortModel> models = Lists.newArrayList();
						models.add(portModel);
						portMap.put(portModel.getNetworkUuid(), models);
					}
				}
				logger.info("Start to sync vm port...");
				List<NetworkBean> beans = Lists.newArrayList();
				for (String key : portMap.keySet()) {
					List<PortModel> portList = portMap.get(key);
					if (!portList.isEmpty()) {
						NetworkBean networkBean = networkMap.get(key);
						List<AddressBean> addresses = Lists.newArrayList();
						for (PortModel pModel : portList) {
							AddressBean address = subnetMap.get(pModel.getPortFixedIps().get(0).getSubnetUuid());
							address.setAddress(pModel.getPortFixedIps().get(0).getIpAddress());
							address.setPortId(pModel.getPortId());
							address.setPortUuid(pModel.getPortUuid());
							address.setQosPolicyUuid(qosPolicy.getPolicyUuid());
							address.setMaxKbps(qosPolicy.getMaxKbps());
							addresses.add(address);
						}
						networkBean.setAddresses(addresses);
						beans.add(networkBean);
					}
				}
				// 设置内网所有ip
				cloudServer.setPrivateIps(JSONObject.toJSONString(beans));
				// 保存安全组信息
				if (!StringUtils.isEmpty(server.getGroups())) {
					logger.info("Start to sync vm security group...");
					// 删除旧安全组与虚拟机的关系
					serverSgroupRepository.removeBySid(cloudServer.getId());
					List<String> groups = JSONObject.parseArray(server.getGroups(), String.class);
					for (String group : groups) {
						SecurityGroup securityGroup = securityGroupRepository.getByName(group,
								cloudServer.getTenantUuid());
						if (null != securityGroup) {
							// 保存虚拟机和安全组关系
							serverSgroupRepository.save(new ServerSgroup(cloudServer.getId(), securityGroup.getId()));
						}
					}
					logger.info("End to sync vm security group...");
				}
				if (BocloudStatus.Server.ERROR.name().equals(cloudServer.getStatus())) {
					cloudServer.setStatus(BocloudStatus.Server.EXCEPTION.name());
				}
				cloudServer.setOsCategory(model.getOsCategory());
				cloudServer.setFlavorUuid(model.getFlavorUuid());
				cloudServerRepository.update(cloudServer);
				// 保存标签信息
				List<Long> labelIds = model.getLabelIds();
				if (!ListTool.isEmpty(labelIds)) {
					List<ServerLabel> serverLabels = Lists.newArrayList();
					for (Long labelId : labelIds) {
						serverLabels.add(new ServerLabel(cloudServer.getId(), labelId, "VM", vendor.getId()));
					}
					if (!ListTool.isEmpty(serverLabels)) {
						serverLabelRepository.batchSave(serverLabels);
					}
				}
				// 保存资源
				List<String> ips = Lists.newArrayList();
				if (!StringUtils.isEmpty(cloudServer.getPrivateIps())) {
					List<JSONObject> objects = JSONObject.parseArray(cloudServer.getPrivateIps(), JSONObject.class);
					for (JSONObject object : objects) {
						List<Object> addresses = object.getJSONArray("addresses");
						for (Object address : addresses) {
							if (StringUtils.isEmpty(
									JSONObject.parseObject(JSONObject.toJSONString(address)).getString("address"))) {
								continue;
							}
							ips.add(JSONObject.parseObject(JSONObject.toJSONString(address)).getString("address"));
						}
					}
				}
				resource = resourceRepository.query(ResourceCategory.Computer.name(), ResourceCatalog.LOGICAL.name(),
						cloudServer.getId());
				if (null == resource) {
					resource = new Resource(ResourceCategory.Computer.name(), ResourceCatalog.LOGICAL.name(),
							cloudServer.getId(), JSONObject.toJSONString(ips), cloudServer.getOsCategory(),
							vendor.getId());
					resource.preSave(cloudServer.getName(), cloudServer.getStatus(), userId, context.getTenant());
					resource.setInventory(JSONObject.toJSONString(cloudServer));
					resourceRepository.save(resource);
				} else {
					resource.setInventory(JSONObject.toJSONString(cloudServer));
					resource.setStatus(cloudServer.getStatus());
					resource.setMenderId(userId);
					resource.setCreatorId(userId);
					resource.setGmtModify(new Date());
					resource.setGmtCreate(new Date());
					resource.setPrivateIps(JSONObject.toJSONString(ips));
					resourceRepository.update(resource);
				}
			} else {
				logger.info("Remove the cloned virtual machine failure");
				event = new ResourceEvent(cloudServer.getId(), handler, "失败", userId, new Date(), "VM", vendor.getId(),
						context.getCatalog());
				cloudServerRepository.remove(cloudServer.getId(), userId);
				// 回收IP
				recycleIp(model.getNetworkBeans(), vendor.getId());
				serverLabelRepository.deleteByTarget(cloudServer.getId(), "VM");
			}
			resourceEventRepository.save(event);
		} catch (Exception e) {
			logger.error("Get error message:", e);
			// 回收IP
			recycleIp(model.getNetworkBeans(), vendor.getId());
			return new BocloudResult<>(false, cloudServer, "create fail");
		}
		return result.isSuccess() ? new BocloudResult<>(true, cloudServer, result.getMessage())
				: new BocloudResult<>(false, cloudServer, result.getMessage());
	}

	/**
	 * 更新状态
	 *
	 * @param server
	 * @throws Exception
	 */
	public void updateStatus(CloudServer server, String status) throws Exception {
		if (!status.equalsIgnoreCase(BocloudStatus.Server.BUILDING.name())) {
			server.setStatus(status);
			return;
		}
		Long start = System.currentTimeMillis();
		boolean running = true;
		while (running) {
			// 超时和延时
			if (System.currentTimeMillis() - start > 1000 * 60 * 10) {
				server.setStatus(BocloudStatus.Server.EXCEPTION.name());
				running = false;
			}
			BocloudResult result = serverDriver.detail(server.getInstanceId(), vendor.getUuid(), null);
			if (result.isSuccess()) {
				VMBean bean = JSONObject.parseObject(JSONObject.toJSONString(result.getData()), VMBean.class);
				String state = bean.getStatus();
				// 虚拟机为错误状态
				if (BocloudStatus.Server.ERROR.name().equalsIgnoreCase(state)) {
					server.setStatus(BocloudStatus.Server.EXCEPTION.name());
					running = false;
					break;
				} else if (BocloudStatus.Server.BUILDING.name().equalsIgnoreCase(state)) {
					Thread.sleep(3000L);
				} else {
					server.setStatus(state);
					server.setGmtVmCreate(bean.getGmtVmCreate());
					running = false;
					break;
				}
			} else {
				server.setStatus(BocloudStatus.Server.EXCEPTION.name());
				running = false;
				break;
			}
		}
	}

	/**
	 * 返回随机字符串，同时包含数字、大小写字母
	 *
	 * @param len 字符串长度，不能小于3
	 * @return String 随机字符串
	 */
	public static String randomStr(int len) {
		if (len < 3) {
			throw new IllegalArgumentException("字符串长度不能小于3");
		}
		// 数组，用于存放随机字符
		char[] chArr = new char[len];
		// 为了保证必须包含数字、大小写字母
		chArr[0] = (char) ('0' + PwdRandom.uniform(0, 10));
		chArr[1] = (char) ('A' + PwdRandom.uniform(0, 26));
		chArr[2] = (char) ('a' + PwdRandom.uniform(0, 26));

		char[] codes = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
				'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
				'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
				'z' };
		// charArr[3..len-1]随机生成codes中的字符
		for (int i = 3; i < len; i++) {
			chArr[i] = codes[PwdRandom.uniform(0, codes.length)];
		}

		// 将数组chArr随机排序
		for (int i = 0; i < len; i++) {
			int r = i + PwdRandom.uniform(len - i);
			char temp = chArr[i];
			chArr[i] = chArr[r];
			chArr[r] = temp;
		}

		return new String(chArr);
	}

}
