package com.bocloud.ims.service.resource;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.compute.ServerDriver;
import com.bocloud.cmp.driver.compute.SnapshotBackupDriver;
import com.bocloud.cmp.driver.compute.SnapshotDriver;
import com.bocloud.cmp.driver.storage.VolumeDriver;
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.SnapshotBackupModel;
import com.bocloud.cmp.model.SnapshotGenericParam;
import com.bocloud.cmp.model.SnapshotModel;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.GridBean;
import com.bocloud.common.model.OperateResult;
import com.bocloud.common.model.OperateResult.OperateCategory;
import com.bocloud.common.model.Pager;
import com.bocloud.common.model.Param;
import com.bocloud.common.model.RequestContext;
import com.bocloud.common.model.RequestContext.Catalog;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.common.utils.JSONTools;
import com.bocloud.common.utils.ListTool;
import com.bocloud.common.utils.MapTools;
import com.bocloud.common.utils.ResultTools;
import com.bocloud.ims.entity.common.Project;
import com.bocloud.ims.entity.common.User;
import com.bocloud.ims.entity.resource.CloudServer;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.DataStore;
import com.bocloud.ims.entity.resource.IpPool;
import com.bocloud.ims.entity.resource.Network;
import com.bocloud.ims.entity.resource.OSTenant;
import com.bocloud.ims.entity.resource.ObjectRelation;
import com.bocloud.ims.entity.resource.PortGroup;
import com.bocloud.ims.entity.resource.Region;
import com.bocloud.ims.entity.resource.ResourceEvent;
import com.bocloud.ims.entity.resource.ResourceQuota;
import com.bocloud.ims.entity.resource.Server;
import com.bocloud.ims.entity.resource.Snapshot;
import com.bocloud.ims.entity.resource.Switcher;
import com.bocloud.ims.entity.resource.TenantProvider;
import com.bocloud.ims.entity.resource.Volume;
import com.bocloud.ims.entity.resource.ResourceQuota.Action;
import com.bocloud.ims.interfaces.resource.CloudServerService;
import com.bocloud.ims.interfaces.resource.SnapshotService;
import com.bocloud.ims.interfaces.resource.VendorProjectService;
import com.bocloud.ims.repository.resource.CloudServerRepository;
import com.bocloud.ims.repository.resource.CloudVendorRepository;
import com.bocloud.ims.repository.resource.DataStoreRepository;
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.NetworkCardRepository;
import com.bocloud.ims.repository.resource.NetworkHostRepository;
import com.bocloud.ims.repository.resource.NetworkRepository;
import com.bocloud.ims.repository.resource.OSTenantRepository;
import com.bocloud.ims.repository.resource.ObjectRelationRepository;
import com.bocloud.ims.repository.resource.PortGroupRepository;
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.ServerRepository;
import com.bocloud.ims.repository.resource.SnapshotRepository;
import com.bocloud.ims.repository.resource.StoreHostRepository;
import com.bocloud.ims.repository.resource.SwitcherRepository;
import com.bocloud.ims.repository.resource.VolumeRepository;
import com.bocloud.ims.service.internal.CosInternalService;
import com.bocloud.ims.service.internal.SmsProjectService;
import com.bocloud.ims.service.internal.SmsUserService;
import com.bocloud.ims.service.utils.ResourceEventPublisher;
import com.bocloud.ims.service.utils.SyncVmwareUtils;
import com.bocloud.service.lock.BocloudACLock;
import com.bocloud.service.lock.LockFactory;
import com.google.common.collect.Maps;

/**
 * 快照Service接口实现
 *
 * @author dongkai
 */
@Service("snapshotService")
public class SnapshotServiceImpl implements SnapshotService {

	private static Logger logger = LoggerFactory.getLogger(SnapshotServiceImpl.class);
	@Autowired
	private LockFactory lockFactory;
	@Autowired
	private SnapshotRepository snapshotRepository;
	@Autowired
	private CloudVendorRepository cloudVendorRepository;
	@Autowired
	private CloudServerRepository cloudServerRepository;
	@Autowired
	private ServerRepository serverRepository;
	@Autowired
	private NetworkCardRepository networkCardRepository;
	@Autowired
	private NetworkRepository networkRepository;
	@Autowired
	private DataStoreRepository dataStoreRepository;
	@Autowired
	private StoreHostRepository storeHostRepository;
	@Autowired
	private PortGroupRepository portGroupRepository;
	@Autowired
	private SwitcherRepository switcherRepository;
	@Autowired
	private NetworkHostRepository networkHostRepository;
	@Autowired
	private VolumeRepository volumeRepository;
	@Autowired
	private RegionRepository regionRepository;
	@Autowired
	private SnapshotDriver snapshotDriver;
	@Autowired
	private VolumeDriver volumeDriver;
	@Autowired
	private ResourceEventPublisher resourceEventPublisher;
	@Autowired
	private IpRepository ipRepository;
	@Autowired
	private IpPoolRepository ipPoolRepository;
	@Autowired
	private ImageRepository imageRepository;
	@Autowired
	private ResourceRepository resourceRepository;
	@Autowired
	private AmqpTemplate amqpTemplate;
	@Autowired
	private CloudServerService cloudServerService;
	@Autowired
	private ServerDriver serverDriver;
	@Autowired
	private SnapshotBackupDriver snapshotBackupDriver;
	@Autowired
	private ObjectRelationRepository objectRelationRepository;
	@Autowired
	private CosInternalService cosInternalService;
	@Autowired
	private SmsProjectService smsProjectService;
	@Autowired
	private SmsUserService smsUserService;
	@Autowired
	private VendorProjectService vendorProjectService;
	@Autowired
	private ResourceEventRepository resourceEventRepository;
	@Autowired
	private OSTenantRepository oSTenantRepository;

	@Override
	public BocloudResult<GridBean<Snapshot>> list(Pager pager, RequestContext context) {
		List<Snapshot> list;
		GridBean gridBean;
		int total;
		try {
			int page = pager.getPage();
			int rows = pager.getRows();
			List<Param> params = pager.getParams();
			Map<String, String> sorter = pager.getSorter();
			if (null == sorter) {
				sorter = Maps.newHashMap();
			}
			sorter.put("createTime", Common.ONE);
			Long tenantId = context.getTenant();
			Long projectId = context.getProject();
			// 为租户下的用户
			if (context.getCatalog().equals(Catalog.Tenant)) {
				// 租户能看到 1.属于当前租户的资源 2.租户下所有项目的资源
				List<Project> tenantProjects = smsProjectService.listTenantProjects(context.getTenant());
				List<Long> projectIds = tenantProjects.stream().map(Project::getId).collect(Collectors.toList());
				total = this.snapshotRepository.count(null, context.getTenant(), projectIds, params, null);
				list = this.snapshotRepository.list(page, rows, null, context.getTenant(), projectIds, params, sorter,
						null);
			} else if (context.getCatalog().equals(Catalog.User)) {
				// 用户能看到 1.自己申请的资源 2.自己所在的资源可见项目（资源对项目下所有成员可见）下创建的资源 3.自己管理的项目下的资源
				List<Project> userManagerProjects = smsProjectService.listUserManagerProjects(context.getTarget());
				List<Project> visibleProjects = smsProjectService.listUserVisibleProjects(context.getTarget());
				List<Long> projectIds = new ArrayList<>();
				List<Long> userManagerProjectsIds = userManagerProjects.stream().map(Project::getId)
						.collect(Collectors.toList());
				if (!userManagerProjectsIds.isEmpty()) {
					projectIds.addAll(userManagerProjectsIds);
				}
				List<Long> visibleProjectsIds = visibleProjects.stream().map(Project::getId)
						.collect(Collectors.toList());
				if (!visibleProjectsIds.isEmpty()) {
					projectIds.addAll(visibleProjectsIds);
				}
				total = this.snapshotRepository.count(context.getTarget(), null, projectIds, params, null);
				list = this.snapshotRepository.list(page, rows, context.getTarget(), null, projectIds, params, sorter,
						null);
			} else {
				total = snapshotRepository.count(params);
				list = snapshotRepository.list(page, rows, params, sorter);
			}
			for (Snapshot snapshot : list) {
				Region region = regionRepository.query(snapshot.getRegion());
				CloudVendor cloudVendor = cloudVendorRepository.query(snapshot.getVendorId());
				if (null != cloudVendor) {
					snapshot.setVendorType(cloudVendor.getType());
					snapshot.setVendorName(cloudVendor.getName());
					if (null != region) {
						snapshot.setRegionName(region.getName());
					}
				}
				Volume volume = volumeRepository.query(snapshot.getVolumeId());
				if (null == volume) {
					snapshot.setBootVolume(false);
				} else {
					snapshot.setVolumeName(volume.getName());
					snapshot.setBootVolume(null == volume.getBootVolume() ? false : volume.getBootVolume());
				}
				CloudServer server = cloudServerRepository.query(snapshot.getVmId());
				if (null != server) {
					snapshot.setVmName(server.getName());
				}
			}
			gridBean = GridHelper.getBean(page, rows, total, list);
			return new BocloudResult<>(true, gridBean, "查询成功");
		} catch (Exception e) {
			logger.error("list snapshot failure:", e);
			return new BocloudResult<>(false, "查询失败", null, null);
		}
	}

	@Override
	public BocloudResult<List<Snapshot>> tree(Long parentId, Long vendorId, Long serverId, RequestContext context) {
		try {
			List<Snapshot> snapshots = snapshotRepository.list(parentId, vendorId, serverId);
			for (Snapshot snapshot : snapshots) {
				List<Snapshot> children = snapshotRepository.list(snapshot.getId(), vendorId, serverId);
				if (null != children && !children.isEmpty()) {
					snapshot.setChildren("[]");
				}
			}
			return new BocloudResult<>(true, snapshots, "查询成功");
		} catch (Exception e) {
			logger.error("list dictionary fail:", e);
			return new BocloudResult<>(false, "查询失败", "", "");
		}
	}

	@Override
	public BocloudResult<String> create(Snapshot snapshotParam, RequestContext context) {
		Assert.notNull(snapshotParam, "参数格式错误");
		String name = snapshotParam.getName();
		Long volumeId = snapshotParam.getVolumeId();
		String remark = snapshotParam.getRemark();
		BocloudResult result;
		try {
			// 如果是租户快照 咋进行配额回滚操作
			BocloudResult snapshotQuotasCallBack = this.snapshotQuotasCallBack(context, Action.Order);
			if(snapshotQuotasCallBack.isFailed()) {
				return snapshotQuotasCallBack;
			}
			Volume volume = volumeRepository.query(volumeId);
			Assert.notNull(volume, "云硬盘不存在");
			CloudVendor vendor = cloudVendorRepository.query(volume.getVendorId());
			Assert.notNull(vendor, "平台数据不存在");
			Snapshot oldSnap = snapshotRepository.getByName(vendor.getId(), name);
			if (null != oldSnap) {
				throw new RuntimeException("快照名称已存在");
			}
			SnapshotModel snapshotModel = new SnapshotModel(name, remark, volume.getVolumeUuid(),
					volume.getInstanceId());
			// azure 所需参数 - start
			if (CloudProvider.AZURE.name().equals(vendor.getType())) {
				snapshotModel.setResourceGroupName(volume.getResourceGroupName());
				snapshotModel.setRegionId(volume.getRegionId());
				snapshotModel.setCategory(volume.getCategory());
			}
			// azure 所需参数 - end
			BocloudResult bocloudResult = volumeDriver.snapshot(snapshotModel, vendor.getUuid(),
					snapshotParam.getOsTenantName(), volume.getRegionId());
			if (bocloudResult.isFailed()) {
				return new BocloudResult<>(false, bocloudResult.getMessage());
			}
			Snapshot snapshot = JSONObject.parseObject(JSONObject.toJSONString(bocloudResult.getData()),
					Snapshot.class);
			String status = snapshot.getStatus();
			snapshot.setName(name);
			snapshot.setVolumeId(volumeId);
			snapshot.setZone(volume.getZone());
			snapshot.setStatus(BocloudStatus.Server.BUILDING.name());
			snapshot.setRemark(remark);
			Region reg = regionRepository.getByRegionId(volume.getRegionId(), vendor.getId());
			if (null != reg) {
				snapshot.setRegion(reg.getId());
			}
			snapshot.setRegionId(volume.getRegionId());
			snapshot.preSave(context.getTarget(), context.getTarget(), volume.getVendorId(), volume.getServerId(),
					volume.getTenantId(), context.getProject());
			snapshot.setResourceGroupId(volume.getResourceGroupId());
			snapshot.setSize(volume.getSize());
			snapshot.setTenantId(volume.getTenantId());
			snapshot.setProjectId(volume.getProjectId());
			snapshot.setMenderId(volume.getMenderId());
			snapshot.setCreatorId(volume.getCreatorId());
			snapshot.setCatalog(volume.getCatalog());
			snapshot.setOwnerId(volume.getOwnerId());
			snapshotRepository.save(snapshot);
			result = new BocloudResult<>(true, "创建任务已下发，正在执行...");
			String snapshotId = snapshot.getSnapshotUuid();
			// 开启一个线程更新状态
			new Thread(() -> {
				boolean running = true;
				Date start = new Date();
				String operate = vendor.getType().toLowerCase() + ".snapshot";
				while (running) {
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						logger.error("Get error message：{}", e);
						Thread.currentThread().interrupt();
					}
					SnapshotModel model = new SnapshotModel();
					model.setSnapshotUuid(snapshotId);
					BocloudResult bocloudResult1 = snapshotDriver.detail(vendor.getUuid(), volume.getRegionId(), model);
					Date end = new Date();
					if (end.getTime() - start.getTime() > 1000 * 60 * 15) {
						running = false;
					}
					if (bocloudResult1.isSuccess()) {
						SnapshotModel bean = JSONObject.parseObject(JSONObject.toJSONString(bocloudResult1.getData()),
								SnapshotModel.class);
						if (!snapshotId.equals(bean.getSnapshotUuid())) {
							continue;
						}
						if (bean.getStatus().equals(status) || "CREATING".equalsIgnoreCase(bean.getStatus())
								|| "progressing".equalsIgnoreCase(bean.getStatus())
								|| "pending".equalsIgnoreCase(bean.getStatus())) {
							try {
								Thread.sleep(3000);
							} catch (Exception e) {
								logger.error("thread sleep failure:", e);
							}
							continue;
						}
						snapshot.setStatus(bean.getStatus());
						snapshot.setName(name);
						snapshot.setRemark(remark);
						snapshot.setTenantUuid(volume.getTenantUuid());
						try {
							snapshotRepository.update(snapshot);
							running = false;
							resourceEventPublisher.send(new OperateResult(bocloudResult1.isSuccess(), "快照创建成功!",
									operate, MapTools.simpleMap(Common.VENDORID, vendor.getId()),
									OperateResult.OperateCategory.ResourceEvent, context));
							ResourceEvent resourceEvent = new ResourceEvent(volume.getId(), "快照创建",
									"云硬盘 【" + volume.getName() + "】" + bocloudResult.getMessage() + "！",
									context.getTarget(), new Date(), "STORAGE", volume.getVendorId(),
									context.getCatalog());
							resourceEvent.setResourceName(volume.getName());
							resourceEventRepository.save(resourceEvent);
						} catch (Exception e) {
							logger.error("update status failure:", e);
							snapshotQuotasCallBack(context, Action.Callback);
							resourceEventPublisher.send(new OperateResult(false, "快照创建失败:" + e.getMessage(), operate,
									MapTools.simpleMap(Common.VENDORID, vendor.getId()),
									OperateResult.OperateCategory.ResourceEvent, context));
						}
					}
				}
			}).start();
			return result;
		} catch (Exception e) {
			logger.error("get cloudvendor and reg error:", e);
			snapshotQuotasCallBack(context, Action.Callback);
			return new BocloudResult<>(false, "创建失败:" + e.getMessage());
		}
	}

	@Override
	public BocloudResult<String> remove(Long id, RequestContext context) {
		String path = Snapshot.class.getSimpleName() + "_" + id;
		try (BocloudACLock lock = lockFactory.getACLock(path)) {
			Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
			Snapshot snap = snapshotRepository.query(id);
			if (null == snap) {
				logger.warn("snapshot data not exist");
				return new BocloudResult<>(false, "数据不存在", "", "");
			}
			// 云供应商
			CloudVendor vendor = cloudVendorRepository.query(snap.getVendorId());
			if (null == vendor) {
				return new BocloudResult<>(false, "获取云供应商失败");
			}
			CloudProvider type = CloudProvider.valueOf(vendor.getType());
			switch (type) {
			case VMWARE:
			case H3C:
				CloudServer server = cloudServerRepository.query(snap.getVmId());
				if (null == server) {
					logger.warn("CloudServer data not exist");
					return new BocloudResult<>(false, "虚拟机不存在");
				}
				Server host = serverRepository.query(server.getHostId());
				if (null == host) {
					logger.warn("HostSystem data not exist");
					return new BocloudResult<>(false, "宿主机不存在");
				}
				if (null != host.getMaintained() && host.getMaintained()) {
					return new BocloudResult<>(false, "该快照的虚拟机所在宿主机处于维护模式下，无法执行删除快照任务");
				}
				break;
			default:
				break;
			}
			// 启动一个线程从MQ上获取数据
			new Thread(() -> {
				String operate = vendor.getType().toLowerCase() + ".snapshot";
				try {
					SnapshotModel model = new SnapshotModel();
					model.setSnapshotUuid(snap.getSnapshotUuid());
					BocloudResult result = new BocloudResult<>(false, "快照【" + snap.getName() + "】删除失败");
					switch (type) {
					case VMWARE:
						CloudServer server = cloudServerRepository.query(snap.getVmId());
						if (null != server) {
							model.setVmName(server.getName());
							result = snapshotDriver.remove(vendor.getUuid(), null, model);
						}
						updateSubSnapshot(snap);
						break;
					case MANAGEONE:
						Long volumeId = snap.getVolumeId();
						// 如果volumeID为空 type 为vm 则为整机快照
						if (null == volumeId && "VM".equalsIgnoreCase(snap.getSnapshotType())) {
							result = snapshotDriver.removeServerSnapshot(model, vendor.getUuid());
						} else {
							result = snapshotDriver.remove(vendor.getUuid(), null, model);
						}
						break;
					case H3C:
						CloudServer h3cServer = cloudServerRepository.query(snap.getVmId());
						if (null != h3cServer) {
							model.setInstanceId(h3cServer.getInstanceId());
							model.setName(snap.getName());
						}
						result = snapshotDriver.remove(vendor.getUuid(), snap.getRegionId(), model);
					default:
						result = snapshotDriver.remove(vendor.getUuid(), snap.getRegionId(), model);
						break;
					}
					String content = result.getMessage();
					if (result.isSuccess()) {
						// 是租户端申请的资源
						ObjectRelation objectRelation = objectRelationRepository.get(id,
								ResourceCategory.Snapshot.name());
						if (null != objectRelation && snap.getTenantId() > 0L) {
							objectRelationRepository.deleteByRid(id, ResourceCategory.Snapshot.name());
						}
						if (type == CloudProvider.MANAGEONE && "VM".equalsIgnoreCase(snap.getSnapshotType())) {
							String blockDeviceMapping = snap.getBlockDeviceMapping();
							// 获取整机快照 下面 硬盘的快照
							List<JSONObject> parseArray = JSONObject.parseArray(blockDeviceMapping, JSONObject.class);
							for (JSONObject obj : parseArray) {
								String snapUuid = obj.getString("snapshot_id");
								snapshotRepository.removeBySnapUuid(snapUuid, vendor.getId(), context.getTarget());
							}
						}
						snapshotRepository.remove(id, context.getTarget());
						content = "快照【" + snap.getName() + "】删除成功";
						// 如果是租户快照 咋进行配额回滚操作
						this.snapshotQuotasCallBack(context, Action.Callback);
					}
					resourceEventPublisher.send(new OperateResult(result.isSuccess(), content, operate,
							MapTools.simpleMap("vendorId", vendor.getId()), OperateCategory.ResourceEvent, context));
				} catch (Exception e) {
					logger.error("Get Message Exception:", e);
					resourceEventPublisher.send(new OperateResult(false, "快照【" + snap.getName() + "】删除失败", operate,
							MapTools.simpleMap("vendorId", vendor.getId()), OperateCategory.ResourceEvent, context));
				}
			}).start();
			return new BocloudResult<>(true, "删除任务已经下发，正在执行……");
		} catch (Exception e) {
			logger.error("remove snapshot fail:", e);
			return new BocloudResult<>(false, "删除失败", "", "");
		}
	}
	
	private void updateSubSnapshot(Snapshot currentSnapshot) {
		String path = CloudServer.class.getSimpleName() + "_" + currentSnapshot.getVmId() + "_"
				+ currentSnapshot.getVendorId();
		try (BocloudACLock lock = lockFactory.getACLock(path)) {
			Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
			// 如果是根快照，需要更新子为新的根快照
			Snapshot snap = snapshotRepository.query(currentSnapshot.getId());
			if (null == snap) {
				return;
			}
			List<Snapshot> children = snapshotRepository.list(snap.getId(), snap.getVendorId(), snap.getVmId());
			if (!ListTool.isEmpty(children)) {
				for (Snapshot snapshot : children) {
					snapshot.setParentId(snap.getParentId());
					snapshotRepository.update(snapshot);
				}
			}
		} catch (Exception e) {
			logger.error("更新子快照异常：" + e.getMessage());
		}
	}

	public BocloudResult snapshotQuotasCallBack(RequestContext context, Action action) {
		try {
			if (context.getCatalog().equals(Catalog.User) || context.getCatalog().equals(Catalog.Tenant)) {
				List<ResourceQuota> quotas = new ArrayList<>();
				String snapshotServiceCode = "meta.snapshot";
				quotas.add(new ResourceQuota(snapshotServiceCode, 1L));
				BocloudResult updateQuotas = cosInternalService.updateQuotas(quotas, action, context.getTenant());
				if (updateQuotas.isFailed()) {
					return new BocloudResult<>(false, "快照创建失败：" + updateQuotas.getMessage());
				}
			}
			return new BocloudResult<>(true, "快照创建成功");
		} catch (Exception e) {
			logger.error("快照创建失败：" + e.getMessage());
			return new BocloudResult<>(false, "快照创建失败：" + e.getMessage());
		}
	}

	@Override
	public BocloudResult<Snapshot> detail(Long id) {
		try {
			Snapshot snapshot = snapshotRepository.query(id);
			Region region = regionRepository.query(snapshot.getRegion());
			CloudVendor cloudVendor = cloudVendorRepository.query(snapshot.getVendorId());
			if (null != cloudVendor) {
				if (CloudProvider.OPENSTACK.name().equals(cloudVendor.getType())) {
					snapshot.setVendorName(cloudVendor.getName());
				} else {
					if (null != region) {
						snapshot.setVendorName(cloudVendor.getName());
						snapshot.setRegionName(region.getName());
					}
				}
			}
			if (null != snapshot.getVolumeUuid()) {
				Volume volume = volumeRepository.getByVolumeUuid(snapshot.getVolumeUuid());
				if (null != volume) {
					snapshot.setVolumeName(volume.getName());
				}
			}
			if (!StringUtils.isEmpty(snapshot.getTenantUuid())) {
				OSTenant osTenant = oSTenantRepository.getByTenantUuid(snapshot.getTenantUuid(),
						snapshot.getVendorId());
				if (null != osTenant) {
					snapshot.setOsTenantName(osTenant.getName());
				}
			}
			return new BocloudResult<>(true, snapshot, "查询详情成功");
		} catch (Exception e) {
			logger.error("query volume detail fail:", e);
			return new BocloudResult<>(false, "查询详情失败", "", "");
		}
	}

	@Override
	public BocloudResult<String> revert(Long id, RequestContext context) {
		String path = Snapshot.class.getSimpleName() + "_" + id;
		try (BocloudACLock lock = lockFactory.getACLock(path)) {
			Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
			Snapshot snap = snapshotRepository.query(id);
			if (null == snap) {
				logger.warn("snapshot data not exist");
				return new BocloudResult<>(false, "数据不存在");
			}
			// 云供应商
			CloudVendor vendor = cloudVendorRepository.query(snap.getVendorId());
			if (null == vendor) {
				return new BocloudResult<>(false, "获取云供应商失败");
			}
			CloudProvider type = CloudProvider.valueOf(vendor.getType());
			switch (type) {
			case OPENSTACK:
				boolean reseted = resetCloudServerStatusForRevert(snap.getVmId(),
						BocloudStatus.Server.RESTORING.name());
				if (!reseted) {
					return new BocloudResult<>(false, "更新状态出错");
				}
				break;
			case VMWARE:
				CloudServer server = cloudServerRepository.query(snap.getVmId());
				if (null == server) {
					logger.warn("CloudServer data not exist");
					return new BocloudResult<>(false, "虚拟机不存在");
				}
				if (null != context.getTenant() && 0L != context.getTenant()) {
					// 获取快照当时的配置信息，用来处理配额问题
					BocloudResult result = snapshotDriver.detail(vendor.getUuid(), snap.getSnapshotVal(),
							server.getName());
					if (result.isFailed()) {
						return result;
					}
				}
				Server host = serverRepository.query(server.getHostId());
				if (null == host) {
					logger.warn("HostSystem data not exist");
					return new BocloudResult<>(false, "宿主机不存在");
				}
				if (null != host.getMaintained() && host.getMaintained()) {
					return new BocloudResult<>(false, "该快照的虚拟机所在宿主机处于维护模式下，无法执行恢复当前快照任务");
				}
				break;
			case HUAWEI:
				String volumeUuid = snap.getVolumeUuid();
				Volume volume = volumeRepository.getByVolumeUuid(volumeUuid);
				if (null != volume && !"AVAILABLE".equalsIgnoreCase(volume.getStatus())) {
					logger.warn("当快照源磁盘状态为'可用'时，才可进行快照数据回滚");
					return new BocloudResult<>(false, "当快照源磁盘状态为'可用'时，才可进行快照数据回滚");
				}
				break;
			case TCE:
				Volume tceVolume = volumeRepository.getByVolumeUuid(snap.getVolumeUuid());
				if (null != tceVolume.getBootVolume() && tceVolume.getBootVolume()) {
					CloudServer tceServer = cloudServerRepository.query(tceVolume.getServerId());
					if (!BocloudStatus.Server.STOPPED.name().equalsIgnoreCase(tceServer.getStatus())) {
						logger.warn("当虚机为关机状态才可以进行快照恢复！");
						return new BocloudResult<>(false, "当虚机为关机状态才可以进行快照恢复！");
					}
				}
				break;
			case MANAGEONE:
				CloudServer moServer = cloudServerRepository.query(snap.getVmId());
				if (null == moServer) {
					logger.warn("CloudServer data not exist");
					return new BocloudResult<>(false, "虚拟机不存在");
				}
				if (!BocloudStatus.Server.STOPPED.name().equalsIgnoreCase(moServer.getStatus())) {
					return new BocloudResult<>(false, "当虚机为关机状态才可以进行整机快照恢复！");
				}
				resetCloudServerStatusForRevert(snap.getVmId(), BocloudStatus.Server.RESTORING.name());
				break;
			case ALIYUN:
				CloudServer aliServer = cloudServerRepository.query(snap.getVmId());
				if (null == aliServer || !BocloudStatus.Server.STOPPED.name().equalsIgnoreCase(aliServer.getStatus())) {
					return new BocloudResult<>(false, "执行回滚云盘需要停止实例，并且确保当前云盘没有创建中的快照和没有更换过操作系统，快照服务正常未欠费");
				}
				Volume aliVolume = volumeRepository.getByVolumeUuid(snap.getVolumeUuid());
				if (null == aliVolume || !"IN_USE".equalsIgnoreCase(aliVolume.getStatus())) {
					logger.warn("执行回滚云盘需要停止实例，并且确保当前云盘没有创建中的快照和没有更换过操作系统，快照服务正常未欠费");
					return new BocloudResult<>(false, "执行回滚云盘需要停止实例，并且确保当前云盘没有创建中的快照和没有更换过操作系统，快照服务正常未欠费");
				}
				break;
			default:
				break;
			}
			// 启动一个线程从MQ上获取数据
			new Thread(() -> {
				String operate = vendor.getType().toLowerCase() + ".snapshot";
				try {
					SnapshotModel model = new SnapshotModel();
					model.setSnapshotUuid(snap.getSnapshotUuid());
					BocloudResult result = null;
					switch (type) {
					case OPENSTACK:
						result = revertForOsCloudServer(model, snap, vendor, context);
						break;
					case VMWARE:
						Long vmId = snap.getVmId();
						CloudServer server = cloudServerRepository.query(vmId);
						if (null != server) {
							model.setVmName(server.getName());
							Server host = serverRepository.query(server.getHostId());
							if (null != host) {
								model.setHostName(host.getName());
							}
							result = snapshotDriver.revert(vendor.getUuid(), null, model);
							if (result.isSuccess()) {
								String content = JSONObject.toJSONString(result.getData());
								CloudServer cloudServer = JSONObject.parseObject(content, CloudServer.class);
								// 数据中心的存储信息
								Map<String, DataStore> storeMap = new HashMap<>();
								List<DataStore> stores = dataStoreRepository.listByVdc(host.getVdcId());
								// 数据中心的网络信息
								Map<String, Network> networkMap = Maps.newHashMap();
								Map<String, String> groupMap = Maps.newHashMap();
								List<Network> oldNetworks = networkRepository.listByVdc(host.getVdcId());
								for (Network network : oldNetworks) {
									networkMap.put(network.getNetworkVal(), network);
								}
								List<Switcher> switchers = switcherRepository.listByVdc(host.getVdcId(), "DVSWITCH");
								for (Switcher switcher : switchers) {
									List<PortGroup> groups = portGroupRepository.listBySwitcher(switcher.getId());
									for (PortGroup group : groups) {
										groupMap.put(group.getGroupVal(), switcher.getSwitcherVal());
									}
								}
								for (DataStore store : stores) {
									storeMap.put(store.getStoreVal(), store);
								}
								SyncVmwareUtils utils = new SyncVmwareUtils(cloudServerRepository, dataStoreRepository,
										serverRepository, snapshotRepository, networkRepository, null,
										storeHostRepository, networkCardRepository, portGroupRepository,
										networkHostRepository, null, resourceRepository, ipRepository, imageRepository,
										volumeRepository);
								List<IpPool> pools = ipPoolRepository.listByIpVersion(null);
								utils.mergeServer(server, cloudServer, host.getPowerState(), vendor.getId(),
										host.getId(), context.getTarget(), storeMap, networkMap, groupMap,
										vendor.getType(), pools);
							}
						}
						break;
					case HUAWEI:
					case ALIYUN:
					case TENCENT:
						model.setVolumeUuid(snap.getVolumeUuid());
						result = snapshotDriver.revert(vendor.getUuid(), snap.getRegionId(), model);
						break;
					case TCE:
						model.setVolumeUuid(snap.getVolumeUuid());
						result = snapshotDriver.revert(vendor.getUuid(), snap.getRegionId(), model);
						break;
					case FUSIONCLOUD:
						model.setVolumeUuid(snap.getVolumeUuid());
						Volume volume = volumeRepository.getByVolumeUuid(snap.getVolumeUuid());
						model.setVolumeName(volume.getName());
						result = snapshotDriver.revert(vendor.getUuid(), snap.getRegionId(), model);
						break;
					case MANAGEONE:
						CloudServer moServer = cloudServerRepository.query(snap.getVmId());
						model.setInstanceId(moServer.getInstanceId());
						model.setSnapshotUuid(snap.getSnapshotUuid());
						result = serverDriver.rebuildServer(vendor.getUuid(), model);
						break;
					default:
						break;
					}
					if (null != result && result.isSuccess()) {
						switch (type) {
						case OPENSTACK:
							// 发送请求，刷新虚拟机列表
							operate = vendor.getType().toLowerCase() + ".vm";
							return;
						case MANAGEONE:
							// 发送请求，刷新虚拟机列表
							operate = vendor.getType().toLowerCase() + ".vm";
							resetCloudServerStatusForRevert(snap.getVmId(), BocloudStatus.Server.STOPPED.name());
							return;
						default:
							break;
						}
						resourceEventPublisher.send(new OperateResult(result.isSuccess(), "恢复快照成功", operate,
								MapTools.simpleMap("vendorId", vendor.getId()),
								OperateResult.OperateCategory.ResourceEvent, context));
					} else {
						switch (type) {
						case OPENSTACK:
						case MANAGEONE:
							resetCloudServerStatusForRevert(snap.getVmId(), BocloudStatus.Server.EXCEPTION.name());
							// 发送请求，刷新虚拟机列表
							operate = vendor.getType().toLowerCase() + ".vm";
							break;
						case VMWARE:
							break;
						default:
							break;
						}
						resourceEventPublisher.send(new OperateResult(false, "恢复当前快照失败", operate,
								MapTools.simpleMap("vendorId", vendor.getId()),
								OperateResult.OperateCategory.ResourceEvent, context));
					}
				} catch (Exception e) {
					logger.error("Get Message Exception:", e);
					switch (type) {
					case OPENSTACK:
					case MANAGEONE:
						resetCloudServerStatusForRevert(snap.getVmId(), BocloudStatus.Server.EXCEPTION.name());
						// 发送请求，刷新虚拟机列表
						operate = vendor.getType().toLowerCase() + ".vm";
						break;
					default:
						break;
					}
					resourceEventPublisher.send(new OperateResult(false, "恢复当前快照失败", operate,
							MapTools.simpleMap("vendorId", vendor.getId()), OperateCategory.ResourceEvent, context));
				}
			}).start();
			return new BocloudResult<>(true, "恢复当前快照任务已经下发，正在执行……");
		} catch (Exception e) {
			logger.error("remove snapshot fail:", e);
			return new BocloudResult<>(false, "恢复当前快照失败", "", "");
		}
	}

	private BocloudResult revertForOsCloudServer(SnapshotModel model, Snapshot snap, CloudVendor vendor,
			RequestContext context) throws Exception {
		BocloudResult result;
		CloudServer osCloudServer = cloudServerRepository.get(snap.getVmId());
		String instanceId = osCloudServer.getInstanceId();
		BocloudResult serverDetail = serverDriver.detail(instanceId, vendor.getUuid(), null);
		if (serverDetail.isSuccess()) {
			ServerModel serverModel = (ServerModel) serverDetail.getData();
			if (!BocloudStatus.Server.STOPPED.name().equals(serverModel.getStatus())) { // 如果没有关机,先关机
				serverDriver.stop(instanceId, vendor.getUuid(), null);
			}
		}
		boolean isStopped = false;
		long startTime = System.currentTimeMillis();
		boolean running = true;
		long shutDownTimeout = 5 * 60 * 1000L;
		while (running) {
			if (System.currentTimeMillis() - startTime > shutDownTimeout) {
				running = false;
			}
			serverDetail = serverDriver.detail(instanceId, vendor.getUuid(), null);
			if (serverDetail.isSuccess()) {
				// 判断虚拟机是否关闭
				ServerModel serverModel = (ServerModel) serverDetail.getData();
				if (BocloudStatus.Server.STOPPED.name().equals(serverModel.getStatus())) {
					isStopped = true;
					running = false;
				}
			}
			Thread.sleep(2000L);
		}

		// 如果停止，创建备份，并还原
		if (isStopped) {
			result = getOsRevertResult(vendor.getUuid(), null, model);
		} else {
			result = new BocloudResult<>(false, "快照恢复时，关闭计算机超时");
			return result;
		}
		// 快照恢复成功,开机
		if (result.isSuccess()) {
			BocloudResult startResult = cloudServerService.start(snap.getVmId(), context);
			if (!startResult.isSuccess()) {// 开机任务提交成功
				result = new BocloudResult<>(false, "快照恢复完成，开启虚拟机失败");
			}
		}
		return result;
	}

	private boolean resetCloudServerStatusForRevert(Long cloudServerId, String status) {
		boolean update = false;// 更新虚拟机的状态为快照还原
		try {
			CloudServer cloudServer = cloudServerRepository.get(cloudServerId, true);
			cloudServer.setStatus(status);
			update = cloudServerRepository.update(cloudServer);
		} catch (Exception e) {
			logger.error("设置状态失败", e);
		}
		return update;
	}

	private BocloudResult getOsRevertResult(String vendorUuid, String region, SnapshotModel snapshot) throws Exception {
		String available = "AVAILABLE";
		String inUse = "IN_USE";
		BocloudResult detail = snapshotDriver.detail(vendorUuid, region, snapshot);
		SnapshotModel latestSnapshot = (SnapshotModel) detail.getData();
		if (latestSnapshot == null) {
			logger.error("snapshot [{}] doesnot exsit!", snapshot.getSnapshotUuid());
			return new BocloudResult<>(false, "快照不存在！");
		}
		SnapshotBackupModel snapshotBackup = new SnapshotBackupModel();
		snapshotBackup.setVolumeUuid(latestSnapshot.getVolumeUuid());
		snapshotBackup.setSnapshotUuid(latestSnapshot.getSnapshotUuid());
		snapshotBackup.setName(new SimpleDateFormat("yyyyMMddHHmmss").format(System.currentTimeMillis()) + "_temp");
		SnapshotBackupModel backupModel = null;
		try {
			BocloudResult bocloudResult = snapshotBackupDriver.create(vendorUuid, region, snapshotBackup);
			if (bocloudResult.isSuccess()) {
				backupModel = (SnapshotBackupModel) bocloudResult.getData();
				if (backupModel != null) {
					String backupStatus = backupModel.getStatus();
					boolean running = true;
					long start = System.currentTimeMillis();
					long backupTimeout = 30 * 1000L * 60;
					long restoreTimeout = 60 * 1000L * 60;
					while (running) {
						// 当备份就绪，进行快照回滚
						if (available.equalsIgnoreCase(backupStatus)) {
							// 重置硬盘状态为可用，不然openstack不会还原
							bocloudResult = volumeDriver.resetStatus(backupModel.getVolumeUuid(), vendorUuid, region,
									backupStatus);
							if (bocloudResult.isSuccess()) {
								// 如果重置状态成功, 调用备份还原的接口
								bocloudResult = snapshotBackupDriver.restore(backupModel, vendorUuid, region);

								if (bocloudResult.isSuccess()) {
									while (running) {
										if (System.currentTimeMillis() - start > restoreTimeout) {
											running = false;
										}
										// 获取备份还原的状态
										BocloudResult backupDetail = snapshotBackupDriver.detail(vendorUuid, region,
												backupModel);
										if (backupDetail.isSuccess()) {
											SnapshotBackupModel latestBackupModel = (SnapshotBackupModel) backupDetail
													.getData();
											// 如果备份的状态为可用，说明已经还原完成
											if (available.equalsIgnoreCase(latestBackupModel.getStatus())) {
												volumeDriver.resetStatus(latestBackupModel.getVolumeUuid(), vendorUuid,
														region, inUse);
												return new BocloudResult<>(true, latestBackupModel, "success");
											}
										}
										Thread.sleep(2000L);
									}
								}
							} else {
								return new BocloudResult<>(false, "重置硬盘状态出错");
							}
						} else {
							BocloudResult result = snapshotBackupDriver.detail(vendorUuid, region, backupModel);
							if (result.isSuccess()) {
								backupModel = (SnapshotBackupModel) result.getData();
								backupStatus = backupModel.getStatus();
							}

						}
						Thread.sleep(2000L);
						if (System.currentTimeMillis() - start > backupTimeout) {
							running = false;
						}
					}
					return new BocloudResult<>(false, "失败，操作超时");
				} else {
					return new BocloudResult<>(false, "获取备份失败");
				}

			}
		} catch (Exception e) {
			logger.error("revert snap failed", e);
		} finally {
			// 删除备份
			if (backupModel != null) {
				BocloudResult removeResult = snapshotBackupDriver.remove(vendorUuid, null, backupModel);
				if (!removeResult.isSuccess()) {
					logger.error("delete backup failed", backupModel.getBackupUuid());
				}
			}
		}
		return new BocloudResult<>(false, "revert failed");
	}

	@Override
	public BocloudResult<String> modify(Long id, Snapshot snapshotParam, RequestContext context) {
		if (null == snapshotParam) {
			return new BocloudResult<>(false, "参数格式不正确");
		}
		String name = snapshotParam.getName();
		String remark = snapshotParam.getRemark();
		Long vmId = snapshotParam.getVmId();
		try {
			Snapshot snapshot = snapshotRepository.query(id);
			if (null == snapshot) {
				logger.warn("Snapshot does not exists");
				return new BocloudResult<>(false, "快照不存在");
			}
			CloudVendor vendor = cloudVendorRepository.query(snapshot.getVendorId());
			if (null == vendor) {
				logger.warn("Cloud vendor does not exists");
				return new BocloudResult<>(false, "云平台不存在");
			}
			// 名称不能重复
			if (!CloudProvider.AWS.name().equals(vendor.getType())) {
				if (!snapshot.getName().equals(name)) {
					Snapshot oldSnap = snapshotRepository.getByName(snapshot.getVendorId(), name);
					if (null != oldSnap) {
						return new BocloudResult<>(false, "快照名称已存在");
					}
				}
			}
			SnapshotModel model = new SnapshotModel();
			model.setName(name);
			model.setRemark(remark);
			model.setSnapshotUuid(snapshot.getSnapshotUuid());
			if (null != vmId) {
				CloudServer server = cloudServerRepository.query(vmId);
				if (null == server) {
					return new BocloudResult<>(false, "所属虚拟机不存在");
				}
				model.setVmName(server.getName());
			}
			new Thread(new Runnable() {
				@Override
				public void run() {
					String operate = vendor.getType().toLowerCase() + ".snapshot";
					try {
						BocloudResult result = snapshotDriver.modify(model, vendor.getUuid(), snapshot.getRegionId());
						if (result.isFailed()) {
							resourceEventPublisher.send(new OperateResult(false, "快照编辑失败:" + result.getMessage(),
									operate, null, OperateCategory.ResourceEvent, context));
							return;
						}
						snapshot.setName(name);
						snapshot.setRemark(remark);
						snapshotRepository.update(snapshot);
						resourceEventPublisher.send(new OperateResult(true, "快照编辑成功", operate, null,
								OperateCategory.ResourceEvent, context));
					} catch (Exception e) {
						logger.error("快照编辑失败：" + e.getMessage());
						resourceEventPublisher.send(new OperateResult(true, "快照编辑成功", operate, null,
								OperateCategory.ResourceEvent, context));
					}
				}
			}).start();
			return new BocloudResult<>(true, "任务已下发，正在执行...");
		} catch (Exception e) {
			logger.error("Get error message:", e);
			return new BocloudResult<>(false, "修改失败");
		}
	}

	@Override
	public BocloudResult<String> apply(String params, RequestContext context) {
		JSONObject object = JSONTools.isJSONObj(params);
		// 快照名称
		String name = object.getString(Common.NAME);
		// 硬盘ID
		Long volumeId = object.getLong("volumeId");
		// 描述
		String remark = object.getString("remark");
		// 使用时长
		Integer months = object.getInteger("months");
		// 申请人
		User applyUser = JSONObject.parseObject(object.getString("applyUser"), User.class);
		BocloudResult result;
		try {
			Volume volume = volumeRepository.query(volumeId);
			if (null == volume) {
				logger.warn("get volume failure!");
				return new BocloudResult<>(false, "云硬盘不存在");
			}
			CloudVendor vendor = cloudVendorRepository.query(volume.getVendorId());
			if (null == vendor) {
				logger.warn("get Cloud vendor failure!");
				return new BocloudResult<>(false, "云平台不存在");
			}
			// 快照延期时间不能超过系统盘到期时间 or op平台快照 延期不可以超过硬盘延期
			if (CloudProvider.OPENSTACK.name().equalsIgnoreCase(vendor.getType()) || volume.getBootVolume()) {
				SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
				Calendar currentCalendar = Calendar.getInstance();
				String currentTime = simpleDateFormat.format(new Date());
				currentCalendar.setTime(simpleDateFormat.parse(currentTime));
				currentCalendar.add(Calendar.MONTH, months);
				ObjectRelation volRelation = objectRelationRepository.get(volume.getId(),
						ResourceCategory.Storage.name());
				if (null != volRelation) {
					String expiredTime = simpleDateFormat.format(volRelation.getExpiredTime());
					Date volExpiredTime = simpleDateFormat.parse(expiredTime);
					if (currentCalendar.getTime().after(volExpiredTime)) {
						return new BocloudResult<>(false, vendor.getType().toLowerCase() + ".snapshot",
								"快照延期时间不能超过云硬盘到期时间");
					}
				}
			}
			SnapshotModel snapshotModel = new SnapshotModel(name, remark, volume.getVolumeUuid(),
					volume.getInstanceId());
			BocloudResult bocloudResult;
			TenantProvider provider = vendorProjectService.getAncestorProject(vendor.getId(), context.getTenant());
			if (null == provider) {
				bocloudResult = volumeDriver.snapshot(snapshotModel, vendor.getUuid(), volume.getRegionId());
			} else {
				bocloudResult = volumeDriver.snapshot(snapshotModel, vendor.getUuid(), provider.getProjectName(),
						volume.getRegionId());
			}
			if (null == bocloudResult || !bocloudResult.isSuccess()) {
				return new BocloudResult<>(false, vendor.getType().toLowerCase() + ".snapshot", "申请创建快照失败");
			}
			Snapshot snapshot = JSONObject.parseObject(JSONObject.toJSONString(bocloudResult.getData()),
					Snapshot.class);
			snapshot.setName(name);
			snapshot.setVolumeId(volumeId);
			snapshot.setStatus(BocloudStatus.Server.BUILDING.name());
			snapshot.setRegionId(volume.getRegionId());
			snapshot.setZone(volume.getZone());
			snapshot.preSave(applyUser.getId(), context.getTarget(), volume.getVendorId(), volume.getServerId(),
					volume.getTenantId(), context.getProject());
			snapshot.setOwnerId(context.getTarget());
			snapshotRepository.save(snapshot);
			result = new BocloudResult<>(true, "申请创建快照任务已下发，正在执行...");
			String snapshotId = snapshot.getSnapshotUuid();
			// 开启一个线程更新状态
			new Thread(() -> {
				String operate = vendor.getType().toLowerCase() + ".snapshot";
				String content = "申请快照失败";
				BocloudResult bocloudResult1 = snapshotDriver.getSnapshot(snapshotId, vendor.getUuid(),
						volume.getRegionId());
				if (bocloudResult1.isSuccess()) {
					content = "申请快照成功";
					SnapshotModel bean = JSONObject.parseObject(JSONObject.toJSONString(bocloudResult1.getData()),
							SnapshotModel.class);
					snapshot.setStatus(bean.getStatus());
					snapshot.setName(name);
					snapshot.setRemark(remark);
					snapshot.setTenantUuid(volume.getTenantUuid());
					try {
						snapshotRepository.update(snapshot);
						ObjectRelation relation = new ObjectRelation(applyUser.getId(), snapshot.getId(), false,
								ResourceCategory.Snapshot.name(), context.getCatalog().name(), 0);
						Calendar calendar = Calendar.getInstance();
						calendar.setTime(new Date());
						calendar.add(Calendar.MONTH, months);
						relation.setExpiredTime(calendar.getTime());
						objectRelationRepository.save(relation);
					} catch (Exception e) {
						// 更新订单状态
						cosInternalService.updateStatus(object.getLong("orderId"), "FAILURE", null, null);
						logger.error("update status failure:", e);
						resourceEventPublisher.send(new OperateResult(false, "申请创建快照失败!", operate,
								MapTools.simpleMap(Common.VENDORID, vendor.getId()),
								OperateResult.OperateCategory.ResourceEvent, context));
					}
				}
				// 通知scp进行计费
				NotifyMessage message = new NotifyMessage(context, "云快照申请", content, true, false);
				amqpTemplate.convertAndSend("event.notice.queue", message);
				resourceEventPublisher.send(new OperateResult(bocloudResult1.isSuccess(), content, operate,
						MapTools.simpleMap(Common.VENDORID, vendor.getId()),
						OperateResult.OperateCategory.ResourceEvent, context));
			}).start();
			return result;
		} catch (Exception e) {
			logger.error("get cloudvendor and reg error:", e);
			return new BocloudResult<>(false, "申请创建快照失败!");
		}
	}

	@Override
	public BocloudResult<String> updateExpriedTime(Long resId, Integer months, RequestContext context) {
		String path = Snapshot.class.getSimpleName() + "_" + resId;
		try (BocloudACLock lock = lockFactory.getACLock(path)) {
			Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
			ObjectRelation relation = objectRelationRepository.get(resId, ResourceCategory.Snapshot.name());
			if (null == relation) {
				return new BocloudResult<>(false, "查织机构资源实体信息失败!");
			}
			BocloudResult<User> userResult = smsUserService.detail(relation.getTarget());
			if (userResult.isFailed()) {
				return new BocloudResult<>(false, "申请人不存在，云快照延期失败");
			}
			User user = userResult.getData();
			if (null == user) {
				return new BocloudResult<>(false, "申请人不存在，云快照延期失败");
			}
			Snapshot snapshot = snapshotRepository.query(resId);
			if (null == snapshot) {
				return new BocloudResult<>(false, "快照不存在");
			}
			CloudVendor cloudVendor = cloudVendorRepository.query(snapshot.getVendorId());
			if (null == cloudVendor) {
				return new BocloudResult<>(false, "平台不存在");
			}
			// vc快照延期 不对硬盘做校验
			Volume volume = null;
			boolean isVmware = CloudProvider.VMWARE.name().equalsIgnoreCase(cloudVendor.getType());
			if (!isVmware) {
				volume = volumeRepository.query(snapshot.getVolumeId());
				if (null == volume) {
					return new BocloudResult<>(false, "快照所在云硬盘不存在");
				}
			}
			Calendar calendar = Calendar.getInstance();
			// 如果快照是启动盘快照 huo 平台为 op or vc，则延期时间不能超过启动盘所在虚拟机的到期时间
			if (isVmware || (null != volume && volume.getBootVolume())) {
				SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
				Date snapExpiredTime = simpleDateFormat.parse(simpleDateFormat.format(relation.getExpiredTime()));
				calendar.setTime(snapExpiredTime);
				calendar.add(Calendar.MONTH, months);

				Long serverId = null;
				if (isVmware) {
					serverId = snapshot.getVmId();
				} else {
					serverId = volume.getServerId();
				}
				if (null != serverId && 0L != serverId) {
					CloudServer server = cloudServerRepository.query(serverId);
					if (null != server) {
						ObjectRelation vmRelation = objectRelationRepository.get(server.getId(),
								ResourceCategory.Computer.name());
						if (null != vmRelation) {
							Date vmExpiredTime = simpleDateFormat
									.parse(simpleDateFormat.format(vmRelation.getExpiredTime()));
							if (calendar.getTime().after(vmExpiredTime)) {
								return new BocloudResult<>(false, "快照延期时间不能超过虚拟机到期时间");
							}
						}
					}
				}
			}
			calendar.setTime(relation.getExpiredTime());
			calendar.add(Calendar.MONTH, months);
			// 查询关联订单
			BocloudResult bocloudResult = cosInternalService.queryByResourceUuid(snapshot.getSnapshotUuid(),
					ResourceCategory.Snapshot.name());
			if (bocloudResult.isFailed() || null == bocloudResult.getData()) {
				return new BocloudResult<>(false, "快照关联订单不存在");
			}
			boolean flag = objectRelationRepository.updateExpriedTime(resId, calendar.getTime(),
					ResourceCategory.Snapshot.name(), "USER");
			if (!flag) {
				return new BocloudResult<>(false, "快照延期失败!");
			}
			return new BocloudResult<>(true, "快照延期成功!");
		} catch (Exception e) {
			logger.error("update snapshot expried time fail:", e);
			return new BocloudResult<>(false, "快照延期失败!");
		}
	}

	@Override
	public BocloudResult<List<Snapshot>> listBootableSnaps(Long vendorId, String tenantUuid, RequestContext context) {
		try {
			List<Snapshot> snapshots = snapshotRepository.listBootableSnaps(vendorId, tenantUuid, context.getTenant());
			return new BocloudResult<>(true, snapshots, "查询成功");
		} catch (Exception e) {
			logger.error("Get error message：", e);
			return new BocloudResult<>(false, "查询失败");
		}
	}

	@Override
	public BocloudResult<String> batchRemove(List<Long> ids, RequestContext context) {
		if (ListTool.isEmpty(ids)) {
			return new BocloudResult<>(false, "没有需要删除的快照！");
		}
		try {
			for (Long id : ids) {
				BocloudResult result = remove(id, context);
				if (result.isFailed()) {
					return result;
				}
			}
		} catch (Exception e) {
			logger.error("batch remove snapshot fail:", e);
			return new BocloudResult<>(false, "批量删除任务下发失败");
		}
		return new BocloudResult<>(true, "批量删除任务已下发，正在执行...");
	}

	@Override
	public BocloudResult<Integer> count(Long userId, Long projectId, Long tenantId) {
		try {
			List<Param> params = new ArrayList<>();
			Catalog catalog = Catalog.Tenant;
			Long target = tenantId;
			if (null != userId) {
				target = userId;
				catalog = Catalog.User;
			}
			List<Project> projects = smsProjectService.projectsByCondition(target, catalog);
			List<Long> projectIds = new ArrayList<>();
			// 此时查询的是全部用户全部项目的信息
			if (null != projectId && 0L != projectId) {
				projectIds.add(projectId);
			} else if (!ListTool.isEmpty(projects)) {
				projects.forEach(project -> projectIds.add(project.getId()));
			} else {
				// 当前用户不属于任何项目，则登录之后查看不到任何信息
				projectIds.add(-1L);
			}
			Integer total = this.snapshotRepository.count(params, null, projectIds);
			return new BocloudResult<>(true, total, "查询成功");
		} catch (Exception e) {
			logger.error("Get error message：", e);
			return new BocloudResult<>(false, "查询失败");
		}
	}

	@Override
	public BocloudResult snapshots(String condition, RequestContext context) {
		JSONObject object = JSONObject.parseObject(condition);

		String action = object.getString("condition");
		if ("listbootablesnaps".equalsIgnoreCase(action)) { // 查询启动卷下的快照
			Long vendorId = object.getLong("vendorId");
			return this.listBootableSnaps(vendorId, object.getString("tenantUuid"), context);
		} else if ("count".equalsIgnoreCase(action)) {
			Long tenantId = object.getLong("tenantId");
			return this.count(context.getTarget(), object.getLong("projectId"), tenantId);
		} else {
			return ResultTools.formatErrResult();
		}
	}

	@Override
	public BocloudResult<String> operation(Long snapshotId, RequestContext context,
			SnapshotGenericParam snapshotGenericParam) {
		if (null == snapshotGenericParam) {
			return new BocloudResult<>(false, "参数格式错误");
		}
		String action = snapshotGenericParam.getAction();
		if ("revert".equalsIgnoreCase(action)) { // 快照恢复
			return this.revert(snapshotId, context);
		}
		if ("updateExpriedTime".equalsIgnoreCase(action)) { // 更新快照到期时间
			return this.updateExpriedTime(snapshotGenericParam.getResId(), snapshotGenericParam.getMonths(), context);
		}
		return new BocloudResult<>(false, "未知类型");
	}

}
