package com.bocloud.ims.service.resource;

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.compute.SnapshotDriver;
import com.bocloud.cmp.driver.storage.StorageDriver;
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.ImageModel;
import com.bocloud.cmp.model.ServerModel;
import com.bocloud.cmp.model.SnapshotModel;
import com.bocloud.cmp.model.StorageModel;
import com.bocloud.cmp.model.VolBean;
import com.bocloud.cmp.model.VolumeModel;
import com.bocloud.cmp.model.common.*;
import com.bocloud.cmp.model.common.OrderMessage.Operation;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.GridBean;
import com.bocloud.common.model.OperateResult;
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.model.Sign;
import com.bocloud.common.model.SimpleBean;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.DateTools;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.common.utils.IDFactory;
import com.bocloud.common.utils.JSONTools;
import com.bocloud.common.utils.ListTool;
import com.bocloud.common.utils.MapTools;
import com.bocloud.ims.entity.VolumeType;
import com.bocloud.ims.entity.common.Business;
import com.bocloud.ims.entity.common.Project;
import com.bocloud.ims.entity.common.ServiceCategory;
import com.bocloud.ims.entity.common.Tenant;
import com.bocloud.ims.entity.common.User;
import com.bocloud.ims.entity.resource.*;
import com.bocloud.ims.entity.resource.manageone.ManageOneAccount;
import com.bocloud.ims.entity.resource.powervc.PowervcRedisKeyBuilder;
import com.bocloud.ims.interfaces.manageone.ManageOneAccountService;
import com.bocloud.ims.interfaces.resource.LabelService;
import com.bocloud.ims.interfaces.resource.VendorProjectService;
import com.bocloud.ims.interfaces.resource.VolumeService;
import com.bocloud.ims.repository.resource.*;
import com.bocloud.ims.service.internal.CosInternalService;
import com.bocloud.ims.service.internal.SmsBusinessService;
import com.bocloud.ims.service.internal.SmsProjectService;
import com.bocloud.ims.service.internal.SmsTenantService;
import com.bocloud.ims.service.internal.SmsUserService;
import com.bocloud.ims.service.resource.fusionsphere.utils.FusionSphereResourceUtils;
import com.bocloud.ims.service.thread.FusionCloudVolumeBuilder;
import com.bocloud.ims.service.thread.FusionSphereVolumeBuilder;
import com.bocloud.ims.service.thread.ManageOneVolumeBuilder;
import com.bocloud.ims.service.thread.OSVolumeBuilder;
import com.bocloud.ims.service.thread.PublicCloudVolumeBuilder;
import com.bocloud.ims.service.thread.SmartVolumeBuilder;
import com.bocloud.ims.service.thread.TceVolumeBuilder;
import com.bocloud.ims.service.thread.VolumeBuilder;
import com.bocloud.ims.service.transporter.vendor.PowervcTransporter;
import com.bocloud.ims.service.transporter.vendor.SmartxTransporter;
import com.bocloud.ims.service.utils.ResourceEventPublisher;
import com.bocloud.nms.enums.OrderItemStatus;
import com.bocloud.service.lock.BocloudACLock;
import com.bocloud.service.lock.LockFactory;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 块设备Service接口实现
 *
 * @author weiwei
 */
@Service("volumeService")
public class VolumeServiceImpl implements VolumeService {

    private static Logger logger = LoggerFactory.getLogger(VolumeServiceImpl.class);
    private static OperateResult.OperateCategory operateCategory = OperateResult.OperateCategory.ResourceEvent;
    private static final Map<String, ScheduledFuture> SNAPSHOT_FUTURES = new ConcurrentHashMap<>();

    @Autowired
    private LockFactory lockFactory;
    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private VolumeRepository volumeRepository;
    @Autowired
    private ImageVolumeRepository imageVolumeRepository;
    @Autowired
    private VolumeTemplateRepository volumeTemplateRepository;
    @Autowired
    private VolumePoolRepository volumePoolRepository;
    @Autowired
    private CloudVendorRepository cloudVendorRepository;
    @Autowired
    private RegionRepository regionRepository;
    @Autowired
    private SnapshotRepository snapshotRepository;
    @Autowired
    private ImageRepository imageRepository;
    @Autowired
    private VolumeDriver volumeDriver;
    @Autowired
    private SnapshotDriver snapshotDriver;
    @Autowired
    private StorageDriver storageDriver;
    @Autowired
    private ServerDriver serverDriver;
    @Autowired
    private PowervcTransporter powervcTransportor;
    @Autowired
    private SmartxTransporter smartTransporter;
    @Autowired
    private ServerVolumeRepository serverVolumeRepository;
    @Autowired
    private StorageRepository storageRepository;
    @Autowired
    private ResourceEventPublisher resourceEventPublisher;
    @Autowired
    private SmsUserService smsUserService;
    @Autowired
    private ObjectRelationRepository objectRelationRepository;
    @Autowired
    private CloudServerRepository cloudServerRepository;
    @Autowired
    private SmsProjectService smsProjectService;
    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    private ZoneRepository zoneRepository;
    @Autowired
    private ResourceEventRepository resourceEventRepository;
    @Autowired
    private StorageHostVolumeRepository storageHostVolumeRepository;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private VolumeTypeRepository volumeTypeRepository;
    @Autowired
    private VendorProjectService vendorProjectService;
    @Autowired
    private StorageViewGroupRepository viewGroupRepository;
    @Autowired
    private OSTenantRepository osTenantRepository;
    @Autowired
    private ManageOneAccountService accountService;
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;
    @Autowired
    private ResourceGroupRepository resourceGroupRepository;
    @Autowired
    private SmsBusinessService smsBusinessService;
    @Autowired
    private SmsTenantService smsTenantService;
    @Autowired
    private LabelService labelService;
    @Autowired
    private CosInternalService cosInternalService;
    @Autowired
    private DataStoreRepository dataStoreRepository;
    @Autowired
    private VdcRepository vdcRepository;
    @Autowired
    private PoolGroupRelationRepository poolGroupRelationRepository;
    @Autowired
    private PoolGroupRepository poolGroupRepository;
    @Autowired
    private FusionSphereResourceUtils fusionSphereResourceUtils;

    private ThreadPoolTaskScheduler taskScheduler;

    public VolumeServiceImpl() {
        taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(Runtime.getRuntime().availableProcessors());
        taskScheduler.setThreadNamePrefix("TimeInspect-");
        taskScheduler.initialize();
    }

    @Override
    public BocloudResult<GridBean<Volume>> list(Pager pager, RequestContext context) {

        int page = pager.getPage();
        int rows = pager.getRows();
        List<Param> params = pager.getParams();
        Map<String, String> sorter = pager.getSorter();
        boolean simple = pager.getSimple();

        List<Volume> list = Lists.newArrayList();
        int total = 0;
        GridBean gridBean = null;
        try {
            if (null == params) {
                params = new ArrayList<>();
            }
            if (null == sorter) {
                sorter = Maps.newHashMap();
            }
            sorter.put("gmtCreate", Common.ONE);
            Long tenantId = context.getTenant();

            String vendorType = null;
            String labelContent = null;
            for (Param param : params) {
                Map<String, Object> paramMap = param.getParam();
                if (paramMap.containsKey("vendorType")) {
                    vendorType = String.valueOf(paramMap.get("vendorType"));
                    paramMap.remove("vendorType");
                }
                if (paramMap.containsKey("labelContent")) {
                    labelContent = paramMap.get("labelContent").toString();
                    paramMap.remove("labelContent");
                }
            }
            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.volumeRepository.count(null, context.getTenant(), projectIds, params, vendorType, labelContent);
                list = this.volumeRepository.list(page, rows, null, context.getTenant(), projectIds, params, sorter,
                        vendorType, labelContent);
                list = convertor(list);
                gridBean = new GridBean<>(page, rows, total, list);
            } 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.volumeRepository.count(context.getTarget(), null, projectIds, params, vendorType, labelContent);
                list = this.volumeRepository.list(page, rows, context.getTarget(), null, projectIds, params, sorter,
                        vendorType, labelContent);
                list = convertor(list);
                gridBean = new GridBean<>(page, rows, total, list);
            } else {
                total = volumeRepository.countByExistsLabel(params, labelContent);
                if (simple) {
                    if (0 == tenantId) {
                        params.add(new Param(MapTools.simpleMap(Common.TENANTID, 0), Sign.EQ));
                    }
                    List<SimpleBean> beans = volumeRepository.list(params, sorter, labelContent);
                    gridBean = new GridBean(1, 1, total, beans);
                } else {
                    list = volumeRepository.list(page, rows, params, sorter, labelContent);
                    for (Volume volume : list) {
                        volume.setStorageHostCnt(storageHostVolumeRepository.listByVolume(volume.getId()).size());
                        volume.setSnapshotCount(snapshotRepository.countByVolumeId(volume.getId(), Collections.EMPTY_LIST));
                        volume.setCloudServers(serverVolumeRepository.listByVolumeId(volume.getId()).stream()
                                .map(ServerVolume::getServerId).map(cloudServerRepository::query)
                                .collect(Collectors.toList())
                        );
                        if (null != volume.getDataStoreId()) {
                            Optional.ofNullable(dataStoreRepository.query(volume.getDataStoreId()))
                                    .map(DataStore::getStoreVal)
                                    .ifPresent(volume::setDataStoreUuid);
                        }
                    }
                    gridBean = GridHelper.getBean(page, rows, total, list);
                }
            }
            return new BocloudResult<>(true, gridBean, "查询成功");
        } catch (Exception e) {
            logger.error("list volume failure:", e);
            return new BocloudResult<>(false, "查询失败", null, null);
        }
    }


    private List<Volume> convertor(List<Volume> list) {
        try {
            if (!ListTool.isEmpty(list)) {
                List<Long> tenantIds = new ArrayList<>();
                List<Long> userIds = new ArrayList<>();
                List<Long> businessIds = new ArrayList<>();
                List<Long> projectIds = new ArrayList<>();
                for (Volume volume : list) {
                    if (volume.getTenantId() != null) {
                        tenantIds.add(volume.getTenantId());
                    }
                    if (volume.getBusinessId() != null) {
                        businessIds.add(volume.getBusinessId());
                    }
                    if (volume.getProjectId() != null) {
                        projectIds.add(volume.getProjectId());
                    }
                    if (volume.getCreatorId() != null) {
                        userIds.add(volume.getCreatorId());
                    }
                    if (volume.getOwnerId() != null) {
                        userIds.add(volume.getOwnerId());
                    }
                    if (volume.getMenderId() != null) {
                        userIds.add(volume.getMenderId());
                    }
                }
                Map<Long, String> userMap = smsUserService.listUsersByIds(userIds).stream()
                        .collect(Collectors.toMap(User::getId, User::getName));
                Map<Long, String> projectMap = smsProjectService.listProjectsByIds(projectIds).stream()
                        .collect(Collectors.toMap(Project::getId, Project::getName));
                Map<Long, String> businessMap = smsBusinessService.listBusinesssByIds(businessIds).stream()
                        .collect(Collectors.toMap(Business::getId, Business::getName));
                Map<Long, String> tenantMap = smsTenantService.listTenantsByIds(tenantIds).stream()
                        .collect(Collectors.toMap(Tenant::getId, Tenant::getName));
                for (Volume volume : list) {
                    // 设置云主机归属信息
                    if (volume.getTenantId() != null) {
                        volume.setTenantName(tenantMap.get(volume.getTenantId()));
                    }
                    if (volume.getBusinessId() != null) {
                        volume.setBusinessName(businessMap.get(volume.getBusinessId()));
                    }
                    if (volume.getProjectId() != null) {
                        volume.setProjectName(projectMap.get(volume.getProjectId()));
                    }
                    if (volume.getCreatorId() != null) {
                        volume.setCreatorName(userMap.get(volume.getCreatorId()));
                    }
                    if (volume.getOwnerId() != null) {
                        volume.setOwnerName(userMap.get(volume.getOwnerId()));
                    }
                    if (volume.getMenderId() != null) {
                        volume.setMenderName(userMap.get(volume.getMenderId()));
                    }
                }
            }
        } catch (Exception e) {
            logger.error("获取云硬盘基本信息异常：", e);
        }
        return list;

    }


    @Override
    public BocloudResult<String> create(Volume volumeParam, RequestContext context) {
        Assert.notNull(volumeParam, "参数格式错误");
        Long vendorId = volumeParam.getVendorId();
        String region = volumeParam.getRegion();
        String name = volumeParam.getName();
        Integer size = volumeParam.getSize();
        String remark = volumeParam.getRemark();
        String callback = volumeParam.getCallback();
        Long serverId = volumeParam.getServerId();
        String category = volumeParam.getCategory();
        String period = volumeParam.getPeriod();
        String zone = volumeParam.getZone();
        String regionId = volumeParam.getRegionId();
        Boolean bootVolume = volumeParam.getBootVolume();
        Boolean multiattach = volumeParam.getMultiattach();
        String imageUuid = volumeParam.getImageUuid();
        Long volumeTypeId = volumeParam.getVolumeTypeId();
        String volType = volumeParam.getVolumeType();
        String osTenantName = volumeParam.getOsTenantName();
        String resourceLabel = volumeParam.getResourceLabel();
        try {
            CloudVendor vendor = cloudVendorRepository.query(vendorId);
            Assert.notNull(volumeParam, "云平台不存在");
            Region reg = regionRepository.getByName(region, vendorId);
            if (CloudProvider.OPENSTACK.name().equals(vendor.getType())||CloudProvider.EASYSTACK.name().equals(vendor.getType())) {
                if (null == vendor || null == reg) {
                    logger.error("get region failure!");
                    return new BocloudResult<>(false, "区域不存在!");
                }
            }
            CloudProvider type = CloudProvider.valueOf(vendor.getType());
            VolumeModel model = new VolumeModel();
            model.setName(name);
            model.setSize(size);
            model.setRemark(remark);
            model.setResourceLabel(resourceLabel);
            switch (type) {
                case JDCLOUD:
                    model.setCategory(category);
                    break;
                case ALIYUN:
                    model.setRegionId(regionId);
                    model.setCategory(category);
                    model.setZone(zone);
                    model.setPerformanceLevel(volumeParam.getPerformanceLevel());
                    model.setResourceGroupUuid(volumeParam.getResourceGroupUuid());
                    if (StringUtils.isEmpty(model.getResourceGroupUuid())) {
                        ResourceGroup resourceGroup = resourceGroupRepository.getByName(vendorId, "default");
                        if (null != resourceGroup) {
                            model.setResourceGroupUuid(resourceGroup.getResourceGroupUuid());
                        }
                    }
                    Long aliyunSourceSnapId = volumeParam.getSourceSnapId();
                    if (null != aliyunSourceSnapId && 0L != aliyunSourceSnapId) {
                        Snapshot snapshot = snapshotRepository.query(aliyunSourceSnapId);
                        if (null == snapshot) {
                            return new BocloudResult(false, "源为快照时已选择的快照不存在");
                        }
                        model.setSourceSnapId(aliyunSourceSnapId);
                        model.setSourceSnapUuid(snapshot.getSnapshotUuid());
                    }
                    logger.info("create volume param : " + JSON.toJSONString(model));
                    break;
                case TIANYI:
                    model.setRegionId(regionId);
                    model.setZone(zone);
                    model.setName(name);
                    model.setVolumeType(volumeParam.getType());
                    model.setSize(volumeParam.getSize());
                    model.setBlockCount(1L);
                    break;
                case OPENSTACK:
                case EASYSTACK:
                    Long sourceImgId = volumeParam.getSourceImgId();
                    if (null != sourceImgId && 0L != sourceImgId) {
                        Image image = imageRepository.query(sourceImgId);
                        if (null == image) {
                            return new BocloudResult<>(false, "源为镜像时已选择的镜像不存在");
                        }
                        model.setImageUuid(image.getImageUuid());
                    }
                    Long sourceSnapId = volumeParam.getSourceSnapId();
                    if (null != sourceSnapId && 0L != sourceSnapId) {
                        Snapshot snapshot = snapshotRepository.query(sourceSnapId);
                        if (null == snapshot) {
                            return new BocloudResult<>(false, "源为快照时已选择的快照不存在");
                        }
                        Volume volume = volumeRepository.query(snapshot.getVolumeId());
                        if (null == volume) {
                            return new BocloudResult<>(false, "源为快照时已选择的快照关联卷不存在");
                        }
                        if (null != volume.getBootVolume() && volume.getBootVolume()) {
                            model.setBootVolume(true);
                        } else {
                            model.setBootVolume(false);
                        }
                        model.setSourceSnapUuid(snapshot.getSnapshotUuid());
                    }
                    Long sourceValidId = volumeParam.getSourceValidId();
                    if (null != sourceValidId && 0L != sourceValidId) {
                        Volume volume = volumeRepository.query(sourceValidId);
                        if (null == volume) {
                            return new BocloudResult<>(false, "源为卷时已选择的卷不存在");
                        }
                        model.setSourceVolidUuid(volume.getVolumeUuid());
                    }
                    if (null != volumeTypeId && 0L != volumeTypeId) {
                        VolumeType volumeType = volumeTypeRepository.query(volumeTypeId);
                        if (null == volumeType) {
                            return new BocloudResult<>(false, "卷类型不存在");
                        }
                        model.setVolumeType(volumeType.getVolumeTypeUuid());
                    }
                    model.setOsTenantName(osTenantName);
                    break;
                case FUSIONCLOUD:
                    // 前端传递的 key 为 region
                    model.setZone(region);
                    model.setMultiattach(multiattach);
                    if (!StringUtils.isEmpty(volumeParam.getType())) {
                        String vt = volumeParam.getType();
                        VolumeType volumeType = volumeTypeRepository.getByName(vt, vendorId);
                        if (null == volumeType) {
                            return new BocloudResult<>(false, "卷类型不存在");
                        }
                        model.setType(volumeType.getName());
                        volumeTypeId = volumeType.getId();
                        volType = volumeType.getName();
                    }
                    break;
                case MANAGEONE:
                    // 前端传递的 key 为 region
                    model.setZone(region);
                    model.setMultiattach(multiattach);
                    if (null != volumeParam.getVolumeTypeId()) {
                        volumeTypeId = volumeParam.getVolumeTypeId();
                        VolumeType volumeType = volumeTypeRepository.query(volumeTypeId);
                        if (null == volumeType) {
                            return new BocloudResult<>(false, "卷类型不存在");
                        }
                        model.setType(volumeType.getName());
                        volType = volumeType.getName();
                    }
                    if (null != volumeParam.getSourceValidId()) {
                        Long sourceVolidId = volumeParam.getSourceValidId();
                        Volume volume = volumeRepository.query(sourceVolidId);
                        if (null == volume) {
                            return new BocloudResult<>(false, "当前卷数据异常！");
                        }
                        model.setSourceVolidUuid(volume.getVolumeUuid());
                        model.setSize(volume.getSize());
                        model.setType(volume.getVolumeType());
                    }
                    break;
                case HUAWEI:
                case HCSO:
                    model.setType(volumeParam.getType());
                    model.setZone(volumeParam.getZone());
                    Long tencentSourceImgId = volumeParam.getSourceImgId();
                    if (null != tencentSourceImgId && 0L != tencentSourceImgId) {
                        Image image = imageRepository.query(tencentSourceImgId);
                        if (null == image) {
                            return new BocloudResult<>(false, "源为镜像时已选择的镜像不存在");
                        }
                        model.setImageUuid(image.getImageUuid());
                        Long minDisk = image.getMinDisk();
                        model.setSize(minDisk.intValue());
                        model.setType(volumeParam.getType());
                    }
                    Long tcSourceSnapId = volumeParam.getSourceSnapId();
                    if (null != tcSourceSnapId && 0L != tcSourceSnapId) {
                        Snapshot snapshot = snapshotRepository.query(tcSourceSnapId);
                        Assert.notNull(snapshot, "源为快照时已选择的快照不存在");
                        Volume volume = volumeRepository.query(snapshot.getVolumeId());
                        Assert.notNull(volume, "源为快照时已选择的快照关联卷不存在");
                        if (null != volume.getBootVolume() && volume.getBootVolume()) {
                            model.setBootVolume(true);
                        } else {
                            model.setBootVolume(false);
                        }
                        model.setSourceSnapUuid(snapshot.getSnapshotUuid());
                        model.setSize(volume.getSize());
                        model.setType(volume.getType() == null ? volume.getVolumeType() : volume.getType());
                    }
                    Long tencentSourceValidId = volumeParam.getSourceValidId();
                    if (null != tencentSourceValidId && 0L != tencentSourceValidId) {
                        Volume volume = volumeRepository.query(tencentSourceValidId);
                        Assert.notNull(volume, "源为卷时已选择的卷不存在");
                        model.setSourceVolidUuid(volume.getVolumeUuid());
                        model.setSize(volume.getSize());
                        model.setType(volume.getType() == null ? volume.getVolumeType() : volume.getType());
                    }
                    break;
                case TENCENT:
                    model.setRemark(remark);
                    model.setName(name);
                    model.setSize(size);
                    model.setDiskChargeType(period);
                    model.setType(category);
                    model.setZone(zone);
                    break;
                case TCE:
                    model.setRemark(remark);
                    model.setName(name);
                    model.setSize(size);
                    model.setDiskChargeType(period);
                    model.setType(category);
                    model.setZone(zone);
                    Long tceSourceSnapId = volumeParam.getSourceSnapId();
                    Snapshot snapshot = snapshotRepository.query(tceSourceSnapId);
                    if (null != snapshot) {
                        model.setSourceSnapshotId(snapshot.getSnapshotUuid());
                    }
                    break;
                case POWERVC:
                    Long templateId = volumeParam.getTemplateId();
                    if (templateId == null) {
                        return new BocloudResult<>(false, "需要提供存储器模版");
                    }
                    VolumeTemplate volumeTemplate = volumeTemplateRepository.get(templateId);
                    if (volumeTemplate == null) {
                        return new BocloudResult<>(false, "未找到存储器模版");
                    }
                    double realSize = size
                            * (volumeTemplate.getCapacityPercent() == null || 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() + "]使用的存储池");
                    }
                    if (basePool.getFreeCapacity() < realSize) {
                        return new BocloudResult<>(false, "存储空间不足，当前存储池[" + basePool.getName() + "]剩余空间："
                                + basePool.getFreeCapacity() + "GB，创建该存储卷需要空间：" + realSize + "GB");
                    }
                    if (volumeTemplate.getCopyPoolId() != null) {
                        VolumePool copyPool = volumePoolRepository.get(volumeTemplate.getCopyPoolId());
                        if (copyPool == null) {
                            return new BocloudResult<>(false, "未找到存储器模板[" + volumeTemplate.getName() + "]使用的存储池");
                        }
                        if (copyPool.getFreeCapacity() < realSize) {
                            return new BocloudResult<>(false, "存储空间不足，当前存储池[" + copyPool.getName() + "]剩余空间："
                                    + copyPool.getFreeCapacity() + "GB，创建该存储卷需要空间：" + realSize + "GB");
                        }
                    }
                    model.setVolumeTemplateUuid(volumeTemplate.getUuid());
                    model.setStorageId(volumeTemplate.getStorageId());
                    model.setMultiattach(multiattach);
                    model.setImageUuid(imageUuid);
                    model.setBootVolume(bootVolume);
                    break;
                case AZURE:
                    Volume volumeByName = volumeRepository.getByName(vendorId, name);
                    if (null != volumeByName) {
                        return new BocloudResult<>(false, "硬盘名称已存在");
                    }
                    ResourceGroup resourceGroup = resourceGroupRepository.query(volumeParam.getResourceGroupId());
                    if (null == resourceGroup) {
                        return new BocloudResult<>(false, "资源组不存在");
                    }
                    Snapshot azureSnapshot = snapshotRepository.query(volumeParam.getSnapshotId());
                    if (null != azureSnapshot) {
                        model.setSourceSnapshotId(azureSnapshot.getSnapshotUuid());
                    }
                    model.setResourceGroupName(resourceGroup.getName());
                    model.setCategory(category);
                    model.setRegionId(regionId);
                    break;
                case AWS:
                    model.setZone(zone);
                    model.setCategory(category);
                    Long awsSourceSnapId = volumeParam.getSourceSnapId();
                    Snapshot awsSnapshot = snapshotRepository.query(awsSourceSnapId);
                    if (null != awsSnapshot) {
                        model.setSourceSnapshotId(awsSnapshot.getSnapshotUuid());
                    }
                    Integer iops = volumeParam.getIops();
                    model.setIops(iops);
                    break;
                case QCLOUD:
                    model.setZone(zone);
                    model.setVolumeType(volType);
                    break;
                case PQCLOUD:
                    model.setZone(zone);
                    model.setVolumeType(volType);
                    break;
                case VOLCENGINE:
                    model.setZone(zone);
                    model.setType(volType);
                    break;
                case SMARTX:
                    Assert.notNull(volumeParam.getTemplateId(), "需要为虚拟卷指定存储策略");
                    VolumeTemplate template = volumeTemplateRepository.get(volumeParam.getTemplateId());
                    Assert.notNull(template, "为找到id为" + volumeParam.getTemplateId() + "的存储策略");

                    Assert.notNull(volumeParam.getName(), "需要为虚拟卷指定名称");
                    Volume volumeOfName = volumeRepository.getByName(vendorId, volumeParam.getName());
                    Assert.isNull(volumeOfName, "该虚拟卷名称已经存在，请重新命名");

                    Assert.notNull(volumeParam.getMultiattach(), "需要为虚拟卷指定类型");

                    model.setName(volumeParam.getName());
                    model.setRemark(volumeParam.getRemark());
                    model.setMultiattach(volumeParam.getMultiattach());
                    model.setSize(volumeParam.getSize());
                    model.setBlockSize(1D);
                    model.setBlockCount(volumeParam.getSize() * 1024L * 1024L * 1024L);
                    model.setVolumeTemplateId(template.getId());
                    model.setVolumeTemplateUuid(template.getUuid());
                    break;
                case FUSIONSPHERE:
                    DataStore dataStore = dataStoreRepository.query(volumeParam.getDataStoreId());
                    Assert.notNull(dataStore, "数据存储不存在");
                    Vdc vdc = vdcRepository.query(dataStore.getVdcId());
                    volumeParam.setVdcId(vdc.getId());
                    Assert.notNull(dataStore, "站点不存在");
                    model.setVdcUri(vdc.getUri());
                    model.setDataStoreUuid(dataStore.getStoreVal());
                    model.setThinlyProvisioned(volumeParam.getThinlyProvisioned());
                    model.setPersistentDisk(volumeParam.getPersistentDisk());
                    model.setIndepDisk(volumeParam.getIndepDisk());
                    model.setVolumeType(volumeParam.getVolumeType());
                    model.setType(volumeParam.getType());
                    break;
                default:
                    return new BocloudResult<>(false, "暂不支持该平台创建云硬盘");
            }
            final Region finalReg = reg;
            final Long finalVolumeTypeId = volumeTypeId;
            final String finalVolType = volType;
            new Thread(() -> {
                String operate = vendor.getType().toLowerCase() + ".volume";
                BocloudResult result = null;
                if (null != finalReg) {
                    result = create(vendor, finalReg.getCode(), region, context, model, serverId, finalVolumeTypeId,
                            finalVolType, volumeParam.getResourceGroupId(), volumeParam);
                } else {
                    result = create(vendor, regionId, null, context, model, serverId, finalVolumeTypeId, finalVolType,
                            volumeParam.getResourceGroupId(), volumeParam);
                }
                resourceEventPublisher.send(new OperateResult(result.isSuccess(), result.getMessage(), operate,
                        MapTools.simpleMap("vendorId", vendorId), OperateResult.OperateCategory.ResourceEvent,
                        context));
                if (!StringUtils.isEmpty(callback)) {
                    BocloudResult bocloudResult = new BocloudResult<>(result.isSuccess(), result.getMessage());
                    if (result.isSuccess()) {
                        bocloudResult.setData(result.getData());
                        Volume volume = (Volume) result.getData();
                        if (null != serverId && 0L != serverId) {
                            VolBean volBean = new VolBean();
                            volBean.setId(volume.getId());
                            volBean.setServerId(serverId);
                            attach(volBean, context);
                        }
                    }
                    amqpTemplate.convertAndSend(callback, JSONObject.toJSON(bocloudResult));
                }
                // 发送给云平台统计队列对云平台重新统计
                JSONObject jsonObject = new JSONObject();
                jsonObject.put(Common.VENDORID, vendor.getId());
                amqpTemplate.convertAndSend("vendor.statistics.queue", jsonObject);
            }).start();
            return new BocloudResult<>(true, "创建任务已下发，正在执行...");
        } catch (Exception e) {
            logger.error("get cloudvendor and reg error:", e);
            return new BocloudResult<>(false, "创建失败：" + e.getMessage());
        }
    }

    /**
     * 云硬盘创建
     *
     * @param vendor
     * @param code
     * @param region
     * @param context
     * @param model
     * @param serverId
     * @param volumeTypeId
     * @param volumeType
     * @return
     */
    private BocloudResult create(CloudVendor vendor, String code, String region, RequestContext context,
                                 VolumeModel model, Long serverId, Long volumeTypeId, String volumeType,
                                 Long resourceGroupId, Volume volumeParam) {
        try {
            BocloudResult bocloudResult = volumeDriver.create(vendor.getUuid(), model.getOsTenantName(), code, model);
            if (CloudProvider.POWERVC.name().equals(vendor.getType())) {
                VolumeModel volumeModel = (VolumeModel) bocloudResult.getData();
                if (volumeModel != null) {
                    // 更新卷信息
                    powervcTransportor.insertOrUpdate(vendor, volumeModel, context.getTarget());
                    // 更新存储池容量
                    if (!StringUtils.isEmpty(volumeModel.getStorageHost())) {
                        Storage storage = storageRepository.get(model.getStorageId());
                        if (storage == null) {
                            return new BocloudResult<>(false, "未找到存储提供者：" + model.getStorageId());
                        }
                        BocloudResult storageResult = storageDriver.detail(vendor.getUuid(), storage.getUuid());
                        if (storageResult.isFailed()) {
                            return new BocloudResult<>(false, "更新存储池容量信息失败：" + storageResult.getMessage());
                        }
                        StorageModel storageModel = (StorageModel) storageResult.getData();
                        powervcTransportor.insertOrUpdate(vendor, storageModel, context.getTarget());
                    }
                }
                // 返回
                return new BocloudResult<>(bocloudResult.isSuccess(), volumeModel,
                        bocloudResult.isSuccess() ? "存储卷[" + model.getName() + "]创建成功"
                                : "存储卷[" + model.getName() + "]创建失败：" + bocloudResult.getMessage());
            } else if (CloudProvider.SMARTX.name().equals(vendor.getType())) {
                Volume volume = null;
                if (bocloudResult.isSuccess()) {
                    String taskUuid = bocloudResult.getData().toString();
                    VendorTaskMsg taskMsg = smartTransporter.getTask(vendor, taskUuid, context.getTarget());
                    if (taskMsg.getSmartFailed()) {
                        return new BocloudResult(false, taskMsg.getSmartFinalErrorMessage());
                    }
                    String volumeUuid = taskMsg.getTargetUuid();
                    bocloudResult = volumeDriver.detail(volumeUuid, vendor.getUuid(), null);
                    if (bocloudResult.isFailed()) {
                        return bocloudResult;
                    }
                    VolumeModel volumeModel = (VolumeModel) bocloudResult.getData();
                    volume = new Volume();
                    smartTransporter.convert(volumeModel, volume);
                    volume.setVendorId(vendor.getId());
                    volume.setTemplateId(model.getVolumeTemplateId());
                    volume.setCreatorId(context.getTarget());
                    volume.setGmtCreate(new Date());
                    volume.setRegionId(region);
                    volumeRepository.save(volume);

                    String message = "虚拟卷 【" + volume.getName() + "】创建成功！";
                    ResourceEvent resourceEvent = new ResourceEvent(volume.getId(), "虚拟卷创建", message,
                            context.getTarget(), new Date(), "STORAGE", vendor.getId(), context.getCatalog());
                    resourceEvent.setResourceName(volume.getName());
                    resourceEventRepository.save(resourceEvent);
                }

                // 返回
                return new BocloudResult<>(bocloudResult.isSuccess(), volume,
                        bocloudResult.isSuccess() ? "虚拟卷[" + model.getName() + "]创建成功"
                                : "虚拟卷[" + model.getName() + "]创建失败：" + bocloudResult.getMessage());
            }

            if (!bocloudResult.isSuccess()) {
                return new BocloudResult<>(false, bocloudResult.getMessage());
            }
            Volume volume = JSONObject.parseObject(JSONObject.toJSONString(bocloudResult.getData()), Volume.class);
            volume.setStorageId(model.getStorageId());
            volume.setStatus(BocloudStatus.Server.BUILDING.name());
            volume.setRegion(code);
            volume.setRegionId(code);
            volume.setZone(model.getZone());
            volume.setRemark(model.getRemark());
            volume.setVolumeTypeId(volumeTypeId);
            volume.setVolumeType(volumeType == null ? model.getType() : volumeType);
            volume.setCatalog(context.getCatalog());
            volume.preSave(context.getTarget(), context.getTarget(), context.getTenant(), vendor.getId(),
                    context.getProject());
            volume.setResourceGroupId(resourceGroupId);
            volume.setResourceLabel(model.getResourceLabel());
            if (CloudProvider.FUSIONSPHERE.name().equals(vendor.getType())) {
                //fc纳管
                volume.setVdcId(volumeParam.getVdcId());
                volume.setPersistentDisk(volumeParam.getPersistentDisk());
                volume.setIndepDisk(volumeParam.getIndepDisk());
                volume.setBootVolume(false);
                volume.setDataStoreId(volumeParam.getDataStoreId());
                volume.setVdcId(volumeParam.getVdcId());
                //fc纳管
            }
            volumeRepository.save(volume);
            Long start = System.currentTimeMillis();
            boolean running = true;
            while (running) {
                if (System.currentTimeMillis() - start > 1000 * 60 * 5) {
                    volume.setStatus(BocloudStatus.Server.EXCEPTION.name());
                    running = false;
                }
                BocloudResult result;
                if (CloudProvider.FUSIONSPHERE.name().equals(vendor.getType())) {
                    result = volumeDriver.detail(volume.getUri(), vendor.getUuid(), code);
                } else {
                    result = volumeDriver.detail(volume.getVolumeUuid(), vendor.getUuid(), code);
                }
                if (result.isSuccess()) {
                    VolumeModel bean = JSONObject.parseObject(JSONObject.toJSONString(result.getData()),
                            VolumeModel.class);
                    String state = bean.getStatus();
                    if ("AVAILABLE".equalsIgnoreCase(state) || "IN_USE".equalsIgnoreCase(state)
                            || "BACKING_UP".equalsIgnoreCase(state) || "UNATTACHED".equalsIgnoreCase(state)
                            || "EXCEPTION".equalsIgnoreCase(state)) {
                        volume.setStatus(state);
                        volume.setBootVolume(bean.getBootVolume());
                        volume.setCreateTime(bean.getCreateTime());
                        if (!CloudProvider.FUSIONSPHERE.name().equals(vendor.getType())) {
                            volume.setDeleteWithInstance(bean.getDeleteWithInstance());
                            volume.setSourceSnapshotId(bean.getSourceSnapshotId());
                        }
                        // 添加平台区别
                        CloudProvider type = CloudProvider.valueOf(vendor.getType());
                        switch (type) {
                            case AWS:
                                volume.setSize(bean.getSize());
                                volume.setCategory(bean.getCategory());
                                volume.setIops(bean.getIops());
                                break;
                            default:
                                break;
                        }
                        running = false;
                    } else {
                        Thread.sleep(3000L);
                    }
                } else {
                    volume.setStatus(BocloudStatus.Server.EXCEPTION.name());
                    running = false;
                }
            }
            volumeRepository.update(volume);
            fusionSphereResourceUtils.modifyDataStore(volume.getDataStoreId(), volume.getSize(), "add");
            String msg = volume.getStatus().equals(BocloudStatus.Server.EXCEPTION.name()) ? "异常" : "成功";
            ResourceEvent resourceEvent = new ResourceEvent(volume.getId(), "云硬盘创建",
                    "云硬盘 【" + volume.getName() + "】创建" + msg + "！", context.getTarget(), new Date(), "STORAGE",
                    vendor.getId(), context.getCatalog());
            resourceEvent.setResourceName(volume.getName());
            resourceEventRepository.save(resourceEvent);
            return new BocloudResult<>(true, volume, "创建云硬盘成功");
        } catch (Exception e) {
            logger.error("create failure:", e);
            return new BocloudResult<>(false, "创建云硬盘失败!");
        }
    }

    @Override
    public BocloudResult<String> remove(Long id, String params, RequestContext context) {
        String path = Volume.class.getSimpleName() + "_" + id;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            Volume volume = volumeRepository.query(id);
            Assert.notNull(volume, "数据不存在");
            CloudVendor vendor = cloudVendorRepository.query(volume.getVendorId());
            Assert.notNull(vendor, "平台不存在");
            String label = CloudProvider.SMARTX.name().equals(vendor.getType()) ? "虚拟卷" : "云硬盘";
            if ("IN_USE".equals(volume.getStatus())) {
                return new BocloudResult<>(false, "正在使用的" + label + "无法删除!");
            }
            // 判断是否存在快照
            Pager pager = new Pager(1, Integer.MAX_VALUE, new ArrayList<>(), new HashMap<>());
            List<Snapshot> snapshots = snapshotRepository.listByVolumeId(volume.getId(), pager);
            if (!ListTool.isEmpty(snapshots)) {
                return new BocloudResult<>(false, label + "存在快照无法删除!");
            }
            if (CloudProvider.POWERVC.name().equals(vendor.getType())) {
                List<ServerVolume> serverVolumes = serverVolumeRepository.listByVolumeId(volume.getId());
                if (serverVolumes != null && serverVolumes.size() > 0) {
                    return new BocloudResult<>(false, "该卷已经附加到云主机，无法删除！");
                }
                List<ImageVolume> imageVolumes = imageVolumeRepository.listByVolume(volume.getId());
                if (imageVolumes != null && imageVolumes.size() > 0) {
                    return new BocloudResult<>(false, "该卷已经附加到映像，无法删除！");
                }
            }

            // 如果是smart需要开启线程进行删除
            if (CloudProvider.SMARTX.name().equals(vendor.getType())) {
                taskExecutor.execute(() -> {
                    OperateResult operateResult = new OperateResult(true, "", vendor.getType().toLowerCase() + ".volume",
                            MapTools.simpleMap("vendorId", vendor.getId()), OperateResult.OperateCategory.ResourceEvent,
                            context);
                    try {
                        // 调用删除接口
                        BocloudResult bocloudResult = volumeDriver.remove(volume.getVolumeUuid(), vendor.getUuid(), volume.getRegionId());
                        if (bocloudResult.isFailed()) {
                            operateResult.setSuccess(false);
                            operateResult.setMessage("虚拟卷删除失败：" + bocloudResult.getMessage());
                            resourceEventPublisher.send(operateResult);
                            return;
                        }

                        // 确认删除任务
                        String taskUuid = bocloudResult.getData().toString();
                        VendorTaskMsg taskMsg = smartTransporter.getTask(vendor, taskUuid, context.getTarget());
                        if (taskMsg.getSmartFailed()) {
                            operateResult.setSuccess(false);
                            operateResult.setMessage("虚拟卷删除失败：" + taskMsg.getSmartFinalErrorMessage());
                            resourceEventPublisher.send(operateResult);
                            return;
                        }

                        // 删除数据库
                        volumeRepository.remove(id, context.getTarget());
                        serverVolumeRepository.removeByVid(id);

                        // 发送给云平台统计队列对云平台重新统计
                        JSONObject jsonObject = new JSONObject();
                        jsonObject.put(Common.VENDORID, vendor.getId());
                        amqpTemplate.convertAndSend("vendor.statistics.queue", jsonObject);

                        // 发送异步消息
                        operateResult.setSuccess(true);
                        operateResult.setMessage("虚拟卷删除成功：" + taskMsg.getSmartFinalErrorMessage());
                        resourceEventPublisher.send(operateResult);
                    } catch (Exception e) {
                        operateResult.setSuccess(false);
                        operateResult.setMessage("虚拟卷删除失败：" + e.getMessage());
                        resourceEventPublisher.send(operateResult);
                    }
                });
                return new BocloudResult<>(true, "任务已经下发，正在执行...");
            }

            //fc调整
            BocloudResult bocloudResult;
            if (CloudProvider.FUSIONSPHERE.name().equals(vendor.getType())) {
                bocloudResult = volumeDriver.remove(volume.getUri(), vendor.getUuid(),
                        volume.getRegionId());
            } else {
                bocloudResult = volumeDriver.remove(volume.getVolumeUuid(), vendor.getUuid(),
                        volume.getRegionId());
            }
            //fc调整
            if (null != bocloudResult && bocloudResult.isFailed()) {
                return new BocloudResult<>(false, bocloudResult.getMessage());
            }
            volumeRepository.remove(id, context.getTarget());
            fusionSphereResourceUtils.modifyDataStore(volume.getDataStoreId(), volume.getSize(), "subtraction");
            ResourceEvent resourceEvent = new ResourceEvent(volume.getId(), label + "删除",
                    label + "【" + volume.getName() + "】删除成功！", context.getTarget(), new Date(), "STORAGE", vendor.getId(),
                    context.getCatalog());
            resourceEvent.setResourceName(volume.getName());
            resourceEventRepository.save(resourceEvent);
            if (CloudProvider.POWERVC.name().equals(vendor.getType())) {
                if (volume.getStorageId() != null) {
                    Storage storage = storageRepository.get(volume.getStorageId());
                    if (storage == null) {
                        return new BocloudResult<>(false, "未找到存储提供者：" + volume.getStorageId());
                    }
                    BocloudResult storageResult = storageDriver.detail(vendor.getUuid(), storage.getUuid());
                    if (storageResult.isFailed()) {
                        return new BocloudResult<>(false, "获取存储提供者详情失败：" + storageResult.getMessage());
                    }
                    StorageModel storageModel = (StorageModel) storageResult.getData();
                    powervcTransportor.insertOrUpdate(vendor, storageModel, context.getTarget());
                }
            }
            // 是否为租户资源
            ObjectRelation objectRelation = objectRelationRepository.get(id, ResourceCategory.Storage.name());
            if (null != objectRelation && volume.getTenantId() > 0L) {
                objectRelationRepository.deleteByRid(id, ResourceCategory.Storage.name());
            }
            // 发送给云平台统计队列对云平台重新统计
            JSONObject jsonObject = new JSONObject();
            jsonObject.put(Common.VENDORID, vendor.getId());
            amqpTemplate.convertAndSend("vendor.statistics.queue", jsonObject);
            return new BocloudResult<>(true, "删除成功");
        } catch (Exception e) {
            logger.error("remove volume fail:", e);
            return new BocloudResult<>(false, "删除失败");
        }
    }

    private void changeOrderStatus(Volume volume, RequestContext context) {
        try {
            // 修改云主机订单状态
            if (!org.springframework.util.StringUtils.isEmpty(volume.getUuid())) {
                OrderMessage orderMessage = new OrderMessage(volume.getUuid(), Operation.Cancelation,
                        OrderItemStatus.UnsubscribeSuccess, null, "云硬盘退订成功", null, null, new ArrayList<>(),
                        ResourceCategory.Storage.name(), context);
                orderMessage.setCategory(ResourceCategory.Storage.name());
                List<QuotaBean> quotas = new ArrayList<>();
                CloudProvider provider = CloudProvider.valueOf(volume.getVendorType());
                switch (provider) {
                    case HUAWEI:
                    case HCSO:
                        quotas.add(new QuotaBean("huawei.stanadard.cbs", 1));
                        break;
                    case TIANYI:
                        quotas.add(new QuotaBean("tianyi.standard.volume", 1));
                        break;
                    default:
                        break;
                }
                quotas.add(new QuotaBean("meta.disk", volume.getSize()));
                orderMessage.setQuotas(quotas);
                logger.info("云硬盘退订 orderMessage ： " + JSON.toJSONString(orderMessage));
                amqpTemplate.convertAndSend("resource.result.queue", orderMessage);

            }
        } catch (Exception e) {
            logger.error("订单状态更新失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult<Volume> detail(Long id) {
        try {
            Volume volume = volumeRepository.query(id);
            if (null == volume) {
                logger.warn("volume data not exist");
                return new BocloudResult<>(false, "数据不存在");
            }
            if (!StringUtils.isEmpty(volume.getTenantUuid())) {
                OSTenant osTenant = osTenantRepository.getByTenantUuid(volume.getTenantUuid(), volume.getVendorId());
                if (null != osTenant) {
                    volume.setOsTenantName(osTenant.getName());
                }
            }
            // 设置云主机归属
            if (null != volume.getOwnerId() && 0L != volume.getOwnerId()) {
                BocloudResult<User> ownerDetail = smsUserService.detail(volume.getOwnerId());
                User owner = ownerDetail.getData();
                if (owner != null) {
                    volume.setOwnerName(owner.getName());
                }
            }
            if (null != volume.getMenderId() && 0L != volume.getMenderId()) {
                BocloudResult<User> menderDetail = smsUserService.detail(volume.getMenderId());
                User mender = menderDetail.getData();
                if (mender != null) {
                    volume.setMenderName(mender.getName());
                }
            }
            if (null != volume.getCreatorId() && 0L != volume.getCreatorId()) {
                BocloudResult<User> creatorDetail = smsUserService.detail(volume.getCreatorId());
                User creator = creatorDetail.getData();
                if (creator != null) {
                    volume.setCreatorName(creator.getName());
                }
            }
            if (null != volume.getProjectId() && 0L != volume.getProjectId()) {
                BocloudResult<Project> projectResult = smsProjectService.detail(volume.getProjectId());
                if (projectResult.isFailed() || null == projectResult.getData()) {
                    return new BocloudResult(false, projectResult.getMessage());
                }
                Project project = projectResult.getData();
                if (null != project) {
                    volume.setProjectName(project.getName());
                }
            }
            if (null != volume.getBusinessId() && 0L != volume.getBusinessId()) {
                BocloudResult<Business> businessDetail = smsBusinessService.detail(volume.getBusinessId());
                Business business = businessDetail.getData();
                if (business != null) {
                    volume.setBusinessName(business.getName());
                }
            }

            // 云供应商
            CloudVendor vendor = cloudVendorRepository.query(volume.getVendorId());
            if (null == vendor) {
                logger.error("get cloudVendor failure");
                return new BocloudResult<>(false, "平台查询失败");
            }
            Region region = null;
            if (CloudProvider.HUAWEI.name().equals(vendor.getType())
                    || CloudProvider.HCSO.name().equals(vendor.getType())
                    || CloudProvider.TENCENT.name().equals(vendor.getType())) {
                region = regionRepository.getByRegionId(volume.getRegionId(), vendor.getId());
                List<Zone> zoneList = zoneRepository.listByZoneId(volume.getZone());
                if (null != zoneList && zoneList.size() > 0) {
                    volume.setZoneName(zoneList.get(0).getName());
                }
            } else {
                region = regionRepository.getByRegionId(volume.getRegionId(), volume.getVendorId());
            }
            if (null != region) {
                volume.setRegionName(region.getName());
            }
            if (CloudProvider.POWERVC.name().equals(vendor.getType()) ||
                    CloudProvider.SMARTX.name().equals(vendor.getType())) {
                if (volume.getTemplateId() != null) {
                    VolumeTemplate volumeTemplate = volumeTemplateRepository.get(volume.getTemplateId());
                    volume.setVolumeTemplate(volumeTemplate);
                }
            }
            if (CloudProvider.SMARTX.name().equals(vendor.getType())) {
                Pager pager = new Pager(1, Integer.MAX_VALUE, new ArrayList<>(), new HashMap<>());
                List<CloudServer> servers = cloudServerRepository.listServerByVolumeId(volume.getId(), pager);
                volume.setCloudServers(servers);
            }
            // 硬盘标签
            List<JSONObject> parseArray = JSON.parseArray(volume.getResourceLabel(), JSONObject.class);
            if (!ListTool.isEmpty(parseArray)) {
                BocloudResult existsValues = labelService.isExistsValues(parseArray);
                if (existsValues.isFailed()) {
                    return existsValues;
                }
                volume.setResourceLabel(JSONObject.toJSONString(existsValues.getData()));
                volumeRepository.update(volume);
            }
            return new BocloudResult<>(true, volume, "查询详情成功");
        } catch (Exception e) {
            logger.error("query volume detail fail:", e);
            return new BocloudResult<>(false, "查询详情失败");
        }
    }

    @Override
    public BocloudResult<List<CloudServer>> servers(Long id) {
        try {
            List<CloudServer> servers = cloudServerRepository.listByVolume(id);
            return new BocloudResult<>(true, servers, "查询成功");
        } catch (Exception e) {
            logger.error("list servers fail:", e);
            return new BocloudResult<>(false, "查询失败");
        }
    }

    @Override
    public BocloudResult listVolumeNotInView(Integer page, Integer rows, Long accessPathId, Long viewId,
                                             List<Param> paramList, Map<String, String> sorter) {
        try {
            StorageViewGroup viewGroup = viewGroupRepository.getById(viewId);
            List<Volume> volumes = volumeRepository.listVolumeNotInView(page, rows, accessPathId, viewGroup.getUuid(),
                    paramList, sorter);
            int total = volumeRepository.countVolumeNotInView(accessPathId, viewGroup.getUuid(), paramList);
            GridBean gridBean = new GridBean(page, rows, total, volumes);
            return new BocloudResult<>(true, gridBean, "查询详情成功");
        } catch (Exception e) {
            logger.error("get volumes fail:", e);
            return new BocloudResult<>(false, "查询详情失败", "", "");
        }
    }

    @Override
    public BocloudResult listVolumeInView(Integer page, Integer rows, Long accessPathId, Long viewId,
                                          List<Param> paramList, Map<String, String> sorter) {
        try {
            StorageViewGroup viewGroup = viewGroupRepository.getById(viewId);
            List<Volume> volumes = volumeRepository.listVolumeInView(page, rows, accessPathId, viewGroup.getUuid(),
                    paramList, sorter);
            int total = volumeRepository.countVolumeInView(accessPathId, viewGroup.getUuid(), paramList);
            GridBean gridBean = new GridBean(page, rows, total, volumes);
            return new BocloudResult<>(true, gridBean, "查询详情成功");
        } catch (Exception e) {
            logger.error("get volumes fail:", e);
            return new BocloudResult<>(false, "查询详情失败", "", "");
        }
    }

    @Override
    public BocloudResult<String> modify(VolBean bean, RequestContext context) {
        String path = Volume.class.getSimpleName() + "_" + bean.getId();
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            Volume volume = volumeRepository.query(bean.getId());
            Assert.notNull(volume, "数据不存在");
            CloudVendor cloudVendor = cloudVendorRepository.query(volume.getVendorId());
            Assert.notNull(cloudVendor, "平台不存在");
            if (!CloudProvider.AWS.name().equals(cloudVendor.getType())
                    && !CloudProvider.ALIYUN.name().equals(cloudVendor.getType())
                    && !CloudProvider.FUSIONSPHERE.name().equals(cloudVendor.getType())) {
                if ("IN_USE".equals(volume.getStatus())) {
                    return new BocloudResult<>(false, "正在使用的云硬盘无法修改!");
                }
            }
            if (CloudProvider.POWERVC.name().equals(cloudVendor.getType())) {
                if (bean.getSize() < volume.getSize()) {
                    return new BocloudResult<>(false, "新的卷容量必须大于旧容量");
                }
                // PBSM-7026 修改管理进来的存储卷失败NullPointerException
                if (bean.getSize() > volume.getSize() && volume.getTemplateId() != null) {
                    VolumeTemplate volumeTemplate = volumeTemplateRepository.get(volume.getTemplateId());
                    if (volumeTemplate != null && volumeTemplate.getCapacityPercent() != null
                            && volumeTemplate.getCapacityPercent() < 0) {
                        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() + "]使用的存储池");
                        }
                        if (basePool.getFreeCapacity() < (bean.getSize() - volume.getSize())) {
                            return new BocloudResult<>(false,
                                    "存储空间不足，当前存储池[" + basePool.getName() + "]剩余空间：" + basePool.getFreeCapacity()
                                            + "GB，扩容该存储卷需要空间：" + (bean.getSize() - volume.getSize()) + "GB");
                        }
                        if (volumeTemplate.getCopyPoolId() != null) {
                            VolumePool copyPool = volumePoolRepository.get(volumeTemplate.getCopyPoolId());
                            if (copyPool == null) {
                                return new BocloudResult<>(false, "未找到存储器模板[" + volumeTemplate.getName() + "]使用的存储池");
                            }
                            if (copyPool.getFreeCapacity() < (bean.getSize() - volume.getSize())) {
                                return new BocloudResult<>(false,
                                        "存储空间不足，当前存储池[" + copyPool.getName() + "]剩余空间：" + copyPool.getFreeCapacity()
                                                + "GB，扩容该存储卷需要空间：" + (bean.getSize() - volume.getSize()) + "GB");
                            }
                        }
                    }
                }
            }
            if (CloudProvider.POWERVC.name().equals(cloudVendor.getType())) {
                // powervc当前只允许修改 是否共享和容量
                volume.setMultiattach(bean.getMultiattach());
                volume.setSize(bean.getSize());
            } else if (CloudProvider.AZURE.name().equals(cloudVendor.getType())) {
                volume.setSize(bean.getSize());
            } else if (CloudProvider.AWS.name().equals(cloudVendor.getType())) {
                volume.setSize(bean.getSize());
                volume.setName(bean.getName());
                if ("io1".equalsIgnoreCase(volume.getCategory())) {
                    if (bean.getSize() * 50 < bean.getIops()) {
                        return new BocloudResult(false, "IOPS 和卷大小之间的最大比率为 50:1");
                    }
                    volume.setIops(bean.getIops());
                }
            } else if (CloudProvider.ALIYUN.name().equals(cloudVendor.getType())) {
                volume.setName(bean.getName());
                volume.setRemark(bean.getRemark());
            } else if (CloudProvider.FUSIONCLOUD.name().equals(cloudVendor.getType())) {
                // FUSIONCLOUD 当前只支持修改名称和描述，且不能走else的代码，否则会丢失multiattach属性
                volume.setName(bean.getName());
                volume.setRemark(bean.getRemark());
            } else if (CloudProvider.SMARTX.name().equals(cloudVendor.getType())) {
                // 如果是smart，需要开启线程
                taskExecutor.execute(() -> {
                    OperateResult operateResult = new OperateResult(true, "", cloudVendor.getType().toLowerCase() + ".volume",
                            MapTools.simpleMap("vendorId", cloudVendor.getId()), OperateResult.OperateCategory.ResourceEvent,
                            context);
                    try {
                        VolumeModel volumeModel = new VolumeModel();
                        volumeModel.setVolumeUuid(volume.getVolumeUuid());
                        volumeModel.setName(bean.getName());
                        volumeModel.setSize(bean.getSize());
                        volumeModel.setBlockSize(1D);
                        volumeModel.setBlockCount(bean.getSize() * 1024L * 1024L * 1024L);
                        volumeModel.setRemark(bean.getRemark());

                        // 调用修改接口
                        BocloudResult bocloudResult = volumeDriver.modify(cloudVendor.getUuid(), null, volumeModel);
                        if (bocloudResult.isFailed()) {
                            operateResult.setSuccess(false);
                            operateResult.setMessage("虚拟卷修改失败：" + bocloudResult.getMessage());
                            resourceEventPublisher.send(operateResult);
                            return;
                        }

                        // 确认修改任务
                        String taskUuid = bocloudResult.getData().toString();
                        VendorTaskMsg taskMsg = smartTransporter.getTask(cloudVendor, taskUuid, context.getTarget());
                        if (taskMsg.getSmartFailed()) {
                            operateResult.setSuccess(false);
                            operateResult.setMessage("虚拟卷修改失败：" + taskMsg.getSmartFinalErrorMessage());
                            resourceEventPublisher.send(operateResult);
                            return;
                        }

                        // 修改数据库
                        volume.setName(bean.getName());
                        volume.setSize(bean.getSize());
                        volume.setBlockSize(1D);
                        volume.setBlockCount(bean.getSize() * 1024L * 1024L * 1024L);
                        volume.setRemark(bean.getRemark());
                        volumeRepository.update(volume);

                        // 重新计算挂载的云主机的磁盘容量数据
                        List<ServerVolume> serverVolumes = serverVolumeRepository.listByVolumeId(volume.getId());
                        for (ServerVolume serverVolume : serverVolumes) {
                            List<Volume> volumes = volumeRepository.listVolumeByServerId(serverVolume.getServerId());
                            CloudServer cloudServer = cloudServerRepository.query(serverVolume.getServerId());
                            cloudServer.setDisk(volumes.stream().mapToInt(Volume::getSize).sum());
                            cloudServerRepository.update(cloudServer);
                        }

                        // 发送异步消息
                        operateResult.setSuccess(true);
                        operateResult.setMessage("虚拟卷修改成功");
                        resourceEventPublisher.send(operateResult);
                    } catch (Exception e) {
                        operateResult.setSuccess(false);
                        operateResult.setMessage("虚拟卷修改失败：" + e.getMessage());
                        resourceEventPublisher.send(operateResult);
                    }
                });
                return new BocloudResult<>(true, "任务已经下发，正在执行...");
            } else if (CloudProvider.FUSIONSPHERE.name().equals(cloudVendor.getType())) {
                if (!StringUtils.isEmpty(bean.getName())) {
                    volume.setName(bean.getName());
                }
                if (null != bean.getSize() && 0 != bean.getSize()) {
                    if (bean.getSize() <= volume.getSize()) {
                        return new BocloudResult(false, "当前磁盘仅能扩大，不可缩小");
                    }
                    volume.setSize(bean.getSize());
                }
            } else {
                bean.setSize(volume.getSize());
                // 这个东西何时杜绝？风险较大！如果bean继续增加和volume同名字段
                // 则执行修改时，只要某个平台的云硬盘页面前端没有传此参数则必然会使数据库丢失值
                BeanUtils.copyProperties(bean, volume);
            }

            taskExecutor.execute(() -> {
                String operate = cloudVendor.getType().toLowerCase() + ".volume";
                String message = "修改磁盘失败";

                CloudServer cloudServer = null;
                Long cloudServerId = volume.getServerId();
                if (cloudServerId != null) {
                    cloudServer = cloudServerRepository.get(cloudServerId);
                }

                //fc的磁盘改名和磁盘扩容是两个接口，所以和其他平台进行区分下
                BocloudResult bocloudResult;
                if (CloudProvider.FUSIONSPHERE.name().equals(cloudVendor.getType())) {
                    VolumeModel model = new VolumeModel();
                    model.setName(bean.getName());
                    model.setSize(bean.getSize());
                    model.setUri(volume.getUri());
                    model.setVolumeUuid(volume.getVolumeUuid());
                    if (null != cloudServer) {
                        model.setInstanceId(cloudServer.getUri());
                    }
                    bocloudResult = volumeDriver.modify(cloudVendor.getUuid(), volume.getRegionId(), model);
                } else {
                    bocloudResult = volumeDriver.modify(cloudVendor.getUuid(), volume.getRegionId(),
                            JSONObject.parseObject(JSONObject.toJSONString(volume), VolumeModel.class));
                }

                try {
                    if (bocloudResult.isSuccess()) {
                        message = "修改磁盘成功";
                        volume.setMenderId(context.getTarget());
                        volumeRepository.update(volume);
                        // 如果是powervc 更新下存储提供者和存储池信息
                        if (CloudProvider.POWERVC.name().equals(cloudVendor.getType())) {
                            Storage storage = storageRepository.get(volume.getStorageId());
                            if (storage != null) {
                                BocloudResult storageResult = storageDriver.detail(cloudVendor.getUuid(), storage.getUuid());
                                StorageModel storageModel = (StorageModel) storageResult.getData();
                                powervcTransportor.insertOrUpdate(cloudVendor, storageModel, context.getTarget());
                            }
                        }

                        // 更新FusionSphere云主机磁盘大小 sxp:2022/8/25
                        if (CloudProvider.FUSIONSPHERE.name().equals(cloudVendor.getType())) {
                            if (cloudServer != null) {
                                List<Volume> volumes = volumeRepository.listByServerId(cloudServerId);
                                cloudServer.setDisk(volumes.stream().mapToInt(Volume::getSize).sum());
                                cloudServerRepository.update(cloudServer);
                            }
                        }

                        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);
                    } else {
                        logger.error("修改磁盘失败：" + bocloudResult.getMessage());
                        message = bocloudResult.getMessage();
                    }
                    resourceEventPublisher.send(new OperateResult(bocloudResult.isSuccess(), message, operate,
                            MapTools.simpleMap("vendorId", cloudVendor.getId()), operateCategory, context));
                } catch (Exception e) {
                    logger.error("modify volume fail:", e);
                    resourceEventPublisher.send(new OperateResult(bocloudResult.isSuccess(), message, operate, MapTools.simpleMap(
                            "vendorId", cloudVendor.getId()), operateCategory, context));
                }
            });
            return new BocloudResult<>(true, "任务已下发，正在执行...");
        } catch (Exception e) {
            logger.error("Modify volume fail:", e);
            return new BocloudResult<>(false, "修改失败", null, null);
        }
    }

    private BocloudResult fusionsphereAttachThread(Volume volume, CloudServer server, CloudVendor vendor, VolBean volBean, RequestContext context) {
        //取消用户手动选择槽位位置，改成后端获取当前槽位+1方式
        Integer seqNum = volumeRepository.getSeqNum(server.getId(), vendor.getId());
        if (seqNum >= 15) {
            return new BocloudResult(false, "已经超出磁盘可挂载的最大限制！");
        }
        taskExecutor.execute(() -> {
            String operate = vendor.getType().toLowerCase() + ".volume";
            String content = "挂载硬盘失败";
            VolumeModel model = new VolumeModel();
            model.setVolumeUuid(volume.getVolumeUuid());
            model.setInstanceId(server.getInstanceId());
            model.setPciType(volBean.getPciType());
            model.setSequenceNum(seqNum + 1);
            model.setIoMode(volBean.getIoMode());
            model.setAccessMode(volBean.getAccessMode());
            BocloudResult result = volumeDriver.attach(vendor.getUuid(), volume.getRegionId(), model, server.getUri());
            try {
                if (result.isSuccess()) {
                    content = "挂载硬盘成功";
                    volume.setStatus("IN_USE");
                    volume.setMenderId(context.getTarget());
                    volume.setServerId(server.getId());
                    volume.setInstanceId(server.getInstanceId());
                    volume.setDevice(result.getData() == null ? null : result.getData().toString());
                    volume.setAttachedTime(new Date());
                    volume.setDetachedTime(null);
                    volume.setPciType(volBean.getPciType());
                    volume.setSequenceNum(seqNum + 1);
                    volume.setIoMode(volBean.getIoMode());
                    volume.setAccessMode(volBean.getAccessMode());
                    volumeRepository.update(volume);

                    Integer oldDisk = server.getDisk();
                    if (null != oldDisk && 0 != oldDisk) {
                        server.setDisk(oldDisk + volume.getSize());
                        cloudServerRepository.update(server);
                    }

                    ResourceEvent resourceEvent = new ResourceEvent(volume.getId(), "云硬盘挂载",
                            "云硬盘 【" + volume.getName() + "】挂载成功！云主机【" + server.getName() + "】", context.getTarget(),
                            new Date(), "STORAGE", vendor.getId(), context.getCatalog());
                    resourceEvent.setResourceName(volume.getName());
                    resourceEventRepository.save(resourceEvent);
                    // 云主机操作
                    ResourceEvent serverResourceEvent = new ResourceEvent(server.getId(), "云硬盘挂载", "挂载成功",
                            context.getTarget(), new Date(), "VM", vendor.getId(), context.getCatalog());
                    resourceEventRepository.save(serverResourceEvent);
                } else {
                    logger.error("挂载硬盘失败：" + result.getMessage());
                    content = result.getMessage();

                    ResourceEvent resourceEvent = new ResourceEvent(volume.getId(), "云硬盘挂载",
                            "云硬盘 【" + volume.getName() + "】挂载失败！云主机【" + server.getName() + "】", context.getTarget(),
                            new Date(), "STORAGE", vendor.getId(), context.getCatalog());
                    resourceEvent.setResourceName(volume.getName());
                    resourceEventRepository.save(resourceEvent);
                    // 添加云主机操作
                    ResourceEvent serverResourceEvent = new ResourceEvent(server.getId(), "云硬盘挂载", "挂载失败",
                            context.getTarget(), new Date(), "VM", vendor.getId(), context.getCatalog());
                    resourceEventRepository.save(serverResourceEvent);
                }
                resourceEventPublisher.send(new OperateResult(result.isSuccess(), content, operate,
                        MapTools.simpleMap("vendorId", vendor.getId()), OperateResult.OperateCategory.ResourceEvent,
                        context));
            } catch (Exception e) {
                logger.error("attach volume to cloud server fail:", e);
                resourceEventPublisher.send(new OperateResult(result.isSuccess(), content, operate,
                        MapTools.simpleMap("vendorId", vendor.getId()), OperateResult.OperateCategory.ResourceEvent,
                        context));
            }
        });
        return new BocloudResult<>(true, "硬盘挂载任务已下发，正在执行...");

    }

    private BocloudResult smartAttachThread(Volume volume, CloudServer server, CloudVendor vendor, RequestContext context) {
        ServerVolume mounted = serverVolumeRepository.getByServerIdAndVolumeId(server.getId(), volume.getId());
        if (mounted != null) {
            return new BocloudResult(false, "云硬盘[" + volume.getName() + "]已经挂载给云主机[" + server.getName() + "]，无需再次挂载");
        }
        taskExecutor.execute(() -> {
            String operate = vendor.getType().toLowerCase() + ".volume";
            String content = "挂载硬盘成功";
            try {
                BocloudResult attachResult = volumeDriver.attach(vendor.getUuid(), null, server.getInstanceId(), volume.getVolumeUuid());
                Assert.isTrue(attachResult.isSuccess(), attachResult.getMessage());
                String taskUuid = attachResult.getData().toString();

                VendorTaskMsg taskMsg = smartTransporter.getTask(vendor, taskUuid, context.getTarget());
                Assert.isTrue(taskMsg.getSmartSucceed(), taskMsg.getSmartFinalErrorMessage());

                BocloudResult detailResult = serverDriver.detail(server.getInstanceId(), vendor.getUuid(), null);
                Assert.isTrue(detailResult.isSuccess(), detailResult.getMessage());
                ServerModel serverModel = (ServerModel) detailResult.getData();

                // 修改状态
                volume.setStatus("IN_USE");
                volume.setMenderId(context.getTarget());
                volume.setAttachedTime(new Date());
                volume.setDetachedTime(null);
                volumeRepository.update(volume);

                // 同步云主机和虚拟卷挂载关系
                List<VolumeModel> volumeModels = serverModel.getDiskDevices().stream()
                        .filter(d -> "disk".equals(d.getType())).collect(Collectors.toList());
                smartTransporter.syncServerVolume(server, volumeModels, context.getTarget());

                ResourceEvent resourceEvent = new ResourceEvent(volume.getId(), "云硬盘挂载",
                        "云硬盘 【" + volume.getName() + "】挂载成功！云主机【" + server.getName() + "】", context.getTarget(),
                        new Date(), "STORAGE", vendor.getId(), context.getCatalog());
                resourceEvent.setResourceName(volume.getName());
                resourceEventRepository.save(resourceEvent);
                // 添加云主机操作
                ResourceEvent serverResourceEvent = new ResourceEvent(server.getId(), "云硬盘挂载", "挂载成功",
                        context.getTarget(), new Date(), "VM", vendor.getId(), context.getCatalog());
                resourceEventRepository.save(serverResourceEvent);
                resourceEventPublisher.send(new OperateResult(attachResult.isSuccess(), content, operate,
                        MapTools.simpleMap("vendorId", vendor.getId()), OperateResult.OperateCategory.ResourceEvent,
                        context));
            } catch (Exception e) {
                logger.error("attach volume to cloud server fail:", e);
                resourceEventPublisher.send(new OperateResult(false, e.getMessage(), operate,
                        MapTools.simpleMap("vendorId", vendor.getId()), OperateResult.OperateCategory.ResourceEvent,
                        context));
            }
        });
        return new BocloudResult<>(true, "任务已下发，正在执行...");
    }

    @Override
    public BocloudResult attach(VolBean volBean, RequestContext context) {
        String path = Volume.class.getSimpleName() + "_" + volBean.getId();
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            Volume volume = volumeRepository.query(volBean.getId());
            if (null == volume) {
                logger.warn("volume data not exist");
                return new BocloudResult<>(false, "数据不存在");
            }
            CloudServer server = cloudServerRepository.query(volBean.getServerId());
            if (null == server) {
                logger.warn("cloud server data not exist");
                return new BocloudResult<>(false, "数据不存在");
            }
            // 云供应商
            CloudVendor vendor = cloudVendorRepository.query(volume.getVendorId());
            if (null == vendor) {
                logger.error("get cloud vendor failure");
                return new BocloudResult<>(false, "所在平台不存在");
            }
            // 解决FusionSphere无法挂载磁盘问题 sxp:2022/8/25
            if (CloudProvider.AZURE.name().equals(vendor.getType())) {
                return attachThread(volume, server, vendor, context);
            }
            if (CloudProvider.ALIYUN.name().equals(vendor.getType())) {
                return aliyunAttachThread(volume, server, vendor, volBean, context);
            }
            if (CloudProvider.FUSIONSPHERE.name().equals(vendor.getType())) {
                return fusionsphereAttachThread(volume, server, vendor, volBean, context);
            }

            taskExecutor.execute(() -> {
                String operate = vendor.getType().toLowerCase() + ".volume";
                String content = "挂载硬盘成功";
                try {
                    BocloudResult result = volumeDriver.attach(vendor.getUuid(), volume.getRegionId(),
                            server.getInstanceId(), volume.getVolumeUuid());
                    if (result.isFailed()) {
                        resourceEventPublisher.send(new OperateResult(result.isSuccess(), result.getMessage(), operate,
                                MapTools.simpleMap("vendorId", vendor.getId()),
                                OperateResult.OperateCategory.ResourceEvent, context));
                        return;
                    }
                    // 修改状态
                    volume.setStatus("IN_USE");
                    volume.setServerId(volBean.getServerId());
                    volume.setInstanceId(server.getInstanceId());
                    volume.setDevice(result.getData().toString());
                    volumeRepository.update(volume);
                    ResourceEvent resourceEvent = new ResourceEvent(volume.getId(), "云硬盘挂载",
                            "云硬盘 【" + volume.getName() + "】挂载成功！云主机【" + server.getName() + "】", context.getTarget(),
                            new Date(), "STORAGE", vendor.getId(), context.getCatalog());
                    resourceEvent.setResourceName(volume.getName());
                    resourceEventRepository.save(resourceEvent);
                    // 添加云主机操作
                    ResourceEvent serverResourceEvent = new ResourceEvent(volBean.getServerId(), "云硬盘挂载", "挂载成功",
                            context.getTarget(), new Date(), "VM", vendor.getId(), context.getCatalog());
                    resourceEventRepository.save(serverResourceEvent);
                    resourceEventPublisher.send(new OperateResult(result.isSuccess(), content, operate,
                            MapTools.simpleMap("vendorId", vendor.getId()), OperateResult.OperateCategory.ResourceEvent,
                            context));
                } catch (Exception e) {
                    logger.error("attach volume to cloud server fail:", e);
                    resourceEventPublisher.send(new OperateResult(false, e.getMessage(), operate,
                            MapTools.simpleMap("vendorId", vendor.getId()), OperateResult.OperateCategory.ResourceEvent,
                            context));
                }
            });
            return new BocloudResult<>(true, "任务已下发，正在执行...");
        } catch (Exception e) {
            logger.error("attach volume to cloud server fail:", e);
            return new BocloudResult<>(false, "挂载硬盘失败:" + e.getMessage());
        }
    }

    private BocloudResult aliyunAttachThread(Volume volume, CloudServer server, CloudVendor vendor, VolBean volBean,
                                             RequestContext context) {
        taskExecutor.execute(() -> {
            String operate = vendor.getType().toLowerCase() + ".volume";
            String content = "挂载硬盘失败";
            VolumeModel model = new VolumeModel();
            model.setVolumeUuid(volume.getVolumeUuid());
            model.setInstanceId(server.getInstanceId());
            model.setDeleteWithInstance(volBean.getDeleteWithInstance());
            BocloudResult result = volumeDriver.attach(vendor.getUuid(), volume.getRegionId(), model);
            try {
                if (result.isSuccess()) {
                    content = "挂载硬盘成功";
                    volume.setStatus("IN_USE");
                    volume.setServerId(server.getId());
                    volume.setInstanceId(server.getInstanceId());
                    volume.setDevice(result.getData() == null ? null : result.getData().toString());
                    volume.setDeleteWithInstance(volBean.getDeleteWithInstance());
                    volume.setAttachedTime(new Date());
                    volume.setDetachedTime(null);
                    volumeRepository.update(volume);
/*                    //需求变更 云主机规格只统计系统盘大小
                    Integer oldDisk = server.getDisk();
                    if (null != oldDisk && 0 != oldDisk) {
                        server.setDisk(oldDisk + volume.getSize());
                        cloudServerRepository.update(server);
                    }*/
                    ResourceEvent resourceEvent = new ResourceEvent(volume.getId(), "云硬盘挂载",
                            "云硬盘 【" + volume.getName() + "】挂载成功！云主机【" + server.getName() + "】", context.getTarget(),
                            new Date(), "STORAGE", vendor.getId(), context.getCatalog());
                    resourceEvent.setResourceName(volume.getName());
                    resourceEventRepository.save(resourceEvent);
                    // 云主机操作
                    ResourceEvent serverResourceEvent = new ResourceEvent(server.getId(), "云硬盘挂载", "挂载成功",
                            context.getTarget(), new Date(), "VM", vendor.getId(), context.getCatalog());
                    resourceEventRepository.save(serverResourceEvent);
                } else {
                    logger.error("挂载硬盘失败：" + result.getMessage());
                    if (CloudProvider.AZURE.name().equals(vendor.getType())) {
                        content = result.getMessage();
                    }

                    ResourceEvent resourceEvent = new ResourceEvent(volume.getId(), "云硬盘挂载",
                            "云硬盘 【" + volume.getName() + "】挂载失败！云主机【" + server.getName() + "】", context.getTarget(),
                            new Date(), "STORAGE", vendor.getId(), context.getCatalog());
                    resourceEvent.setResourceName(volume.getName());
                    resourceEventRepository.save(resourceEvent);
                    // 添加云主机操作
                    ResourceEvent serverResourceEvent = new ResourceEvent(server.getId(), "云硬盘挂载", "挂载失败",
                            context.getTarget(), new Date(), "VM", vendor.getId(), context.getCatalog());
                    resourceEventRepository.save(serverResourceEvent);
                }
                resourceEventPublisher.send(new OperateResult(result.isSuccess(), content, operate,
                        MapTools.simpleMap("vendorId", vendor.getId()), OperateResult.OperateCategory.ResourceEvent,
                        context));
            } catch (Exception e) {
                logger.error("attach volume to cloud server fail:", e);
                resourceEventPublisher.send(new OperateResult(result.isSuccess(), content, operate,
                        MapTools.simpleMap("vendorId", vendor.getId()), OperateResult.OperateCategory.ResourceEvent,
                        context));
            }
        });
        return new BocloudResult<>(true, "硬盘挂载任务已下发，正在执行...");

    }

    private BocloudResult attachThread(Volume volume, CloudServer server, CloudVendor vendor, RequestContext context) {
        taskExecutor.execute(() -> {
            String operate = vendor.getType().toLowerCase() + ".volume";
            String content = "挂载硬盘失败";
            BocloudResult result = volumeDriver.attach(vendor.getUuid(), volume.getRegionId(), server.getInstanceId(),
                    volume.getVolumeUuid());
            try {
                if (result.isSuccess()) {
                    content = "挂载硬盘成功";
                    if (CloudProvider.AZURE.name().equals(vendor.getType())) {
                        volume.setStatus("IN_USE");
                        volume.setMenderId(context.getTarget());
                        volume.setServerId(server.getId());
                        volume.setInstanceId(server.getInstanceId());
                        volumeRepository.update(volume);
                    }
                    ResourceEvent resourceEvent = new ResourceEvent(volume.getId(), "云硬盘挂载",
                            "云硬盘 【" + volume.getName() + "】挂载成功！云主机【" + server.getName() + "】", context.getTarget(),
                            new Date(), "STORAGE", vendor.getId(), context.getCatalog());
                    resourceEvent.setResourceName(volume.getName());
                    resourceEventRepository.save(resourceEvent);
                    // 添加云主机操作
                    ResourceEvent serverResourceEvent = new ResourceEvent(server.getId(), "云硬盘挂载", "挂载成功",
                            context.getTarget(), new Date(), "VM", vendor.getId(), context.getCatalog());
                    resourceEventRepository.save(serverResourceEvent);
                } else {
                    logger.error("挂载硬盘失败：" + result.getMessage());
                    if (CloudProvider.AZURE.name().equals(vendor.getType())) {
                        content = result.getMessage();
                    }

                    ResourceEvent resourceEvent = new ResourceEvent(volume.getId(), "云硬盘挂载",
                            "云硬盘 【" + volume.getName() + "】挂载失败！云主机【" + server.getName() + "】", context.getTarget(),
                            new Date(), "STORAGE", vendor.getId(), context.getCatalog());
                    resourceEvent.setResourceName(volume.getName());
                    resourceEventRepository.save(resourceEvent);
                    // 添加云主机操作
                    ResourceEvent serverResourceEvent = new ResourceEvent(server.getId(), "云硬盘挂载", "挂载失败",
                            context.getTarget(), new Date(), "VM", vendor.getId(), context.getCatalog());
                    resourceEventRepository.save(serverResourceEvent);
                }
                resourceEventPublisher.send(new OperateResult(result.isSuccess(), content, operate,
                        MapTools.simpleMap("vendorId", vendor.getId()), OperateResult.OperateCategory.ResourceEvent,
                        context));
            } catch (Exception e) {
                logger.error("attach volume to cloud server fail:", e);
                resourceEventPublisher.send(new OperateResult(result.isSuccess(), content, operate,
                        MapTools.simpleMap("vendorId", vendor.getId()), OperateResult.OperateCategory.ResourceEvent,
                        context));
            }
        });
        return new BocloudResult<>(true, "硬盘挂载任务已下发，正在执行...");
    }

    @Override
    public BocloudResult detach(VolBean volBean, RequestContext context) {
        String path = Volume.class.getSimpleName() + "_" + volBean.getId();
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            Volume volume = volumeRepository.query(volBean.getId());
            if (null == volume) {
                logger.warn("volume data not exist");
                return new BocloudResult<>(false, "数据不存在");
            }
            if (null != volume.getBootVolume() && volume.getBootVolume() && "IN_USE".equals(volume.getStatus())) {
                return new BocloudResult<>(false, "启动盘不能卸载");
            }
            // 云供应商
            CloudVendor vendor = cloudVendorRepository.query(volume.getVendorId());
            if (null == vendor) {
                logger.error("get cloud vendor failure");
                return new BocloudResult<>(false, "所在平台不存在");
            }
            CloudServer server;
            if (CloudProvider.SMARTX.name().equals(vendor.getType())) {
                if (volBean.getServerId() != null) {
                    server = cloudServerRepository.query(volBean.getServerId());
                    if (null == server) {
                        logger.warn("cloud server data not exist");
                        return new BocloudResult<>(false, "数据不存在");
                    }
                } else {
                    List<ServerVolume> serverVolumes = serverVolumeRepository.listByVolumeId(volBean.getId());
                    if (serverVolumes.isEmpty()) {
                        return new BocloudResult(false, "该云硬盘尚未挂载给任何云主机，无法执行卸载操作");
                    }
                    if (serverVolumes.size() > 1) {
                        return new BocloudResult(false, "该云硬盘挂载了多个云主机，请明确需要卸载的云主机");
                    }
                    server = cloudServerRepository.query(serverVolumes.get(0).getServerId());
                    if (null == server) {
                        logger.warn("cloud server data not exist");
                        return new BocloudResult<>(false, "数据不存在");
                    }
                }
            } else {
                server = cloudServerRepository.query(volume.getServerId());
                if (null == server) {
                    logger.warn("cloud server data not exist");
                    return new BocloudResult<>(false, "数据不存在");
                }
            }
            String serverInstanceId = server.getInstanceId();
            if (CloudProvider.FUSIONSPHERE.name().equals(vendor.getType())) {
                serverInstanceId = server.getUri();
                volume.setPciType(null);
                volume.setSequenceNum(null);
                volume.setIoMode(null);
                volume.setAccessMode(null);
            }
            // 解决FusionSphere无法卸载磁盘问题 sxp:2022/8/25
            BocloudResult result = volumeDriver.detach(vendor.getUuid(), volume.getRegionId(), serverInstanceId,
                    volume.getVolumeUuid());
            if (result.isFailed()) {
                return new BocloudResult<>(false, result.getMessage());
            }
            if (CloudProvider.SMARTX.name().equals(vendor.getType())) {
                String taskUuid = result.getData().toString();
                VendorTaskMsg taskMsg = smartTransporter.getTask(vendor, taskUuid, context.getTarget());
                if (taskMsg.getSmartFailed()) {
                    return new BocloudResult<>(false, taskMsg.getSmartFinalErrorMessage());
                }
            }

            // 修改状态
            volume.setStatus("AVAILABLE");
            volume.setServerId(null);
            volume.setDevice(null);
            volume.setInstanceId(null);
            volume.setAttachedTime(null);
            volume.setDetachedTime(new Date());
            volumeRepository.update(volume);

            //需求变更 云主机规格只统计系统盘大小
            // 数据盘FusionSphere是计算到云主机规格中的 sxp:2022/8/25
            if (CloudProvider.FUSIONSPHERE.name().equals(vendor.getType())) {
                Integer oldDisk = server.getDisk();
                if (null != oldDisk && 0 != oldDisk) {
                    server.setDisk(oldDisk - volume.getSize());
                    cloudServerRepository.update(server);
                }
            }

            if (CloudProvider.SMARTX.name().equals(vendor.getType())) {
                serverVolumeRepository.removeByServerIdAndVolumeId(server.getId(), volume.getId());
                if (volume.getMultiattach() == null || !volume.getMultiattach()) {
                    volumeRepository.remove(volume.getId(), context.getTarget());
                }
            }

            ResourceEvent resourceEvent = new ResourceEvent(volume.getId(), "云硬盘卸载",
                    "云硬盘 【" + volume.getName() + "】卸载成功！云主机【" + server.getName() + "】", context.getTarget(), new Date(),
                    "STORAGE", vendor.getId(), context.getCatalog());
            resourceEvent.setResourceName(volume.getName());
            resourceEventRepository.save(resourceEvent);

            // 添加云主机操作
            ResourceEvent serverResourceEvent = new ResourceEvent(server.getId(), "云硬盘卸载", "卸载成功", context.getTarget(),
                    new Date(), "VM", vendor.getId(), context.getCatalog());
            resourceEventRepository.save(serverResourceEvent);

            return new BocloudResult<>(true, "卸载硬盘成功");
        } catch (Exception e) {
            logger.error("remove volume fail:", e);
            return new BocloudResult<>(false, "卸载硬盘失败");
        }
    }

    @Override
    public BocloudResult snapshot(VolBean volBean, RequestContext context) {
        Assert.notNull(volBean.getId(), "需要指定要生成快照的虚拟卷");
        Volume volume = volumeRepository.query(volBean.getId());
        Assert.notNull(volume, "未找到id为" + volBean.getId() + "的虚拟卷");

        CloudVendor vendor = cloudVendorRepository.query(volume.getVendorId());
        Assert.notNull(vendor, "未找到id为" + volume.getServerId() + "的云平台");

        Assert.notNull(volBean.getName(), "需要指定快照名称");

        SnapshotModel snapshotModel = new SnapshotModel();
        snapshotModel.setVolumeUuid(volume.getVolumeUuid());
        snapshotModel.setName(volBean.getName());
        snapshotModel.setRemark(volBean.getRemark());

        taskExecutor.execute(() -> {
            String path = Volume.class.getSimpleName() + "_" + volume.getId();
            OperateResult operateResult = new OperateResult(true, "", vendor.getType().toLowerCase() + ".volume",
                    MapTools.simpleMap("vendorId", vendor.getId()), OperateResult.OperateCategory.ResourceEvent, context);
            try (BocloudACLock lock = lockFactory.getACLock(path)) {
                // 请求锁
                Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");

                // 调用创建快照接口
                BocloudResult bocloudResult = volumeDriver.snapshot(snapshotModel, vendor.getUuid(), null);
                if (bocloudResult.isFailed()) {
                    operateResult.setSuccess(false);
                    operateResult.setMessage("虚拟卷创建快照失败：" + bocloudResult.getMessage());
                    resourceEventPublisher.send(operateResult);
                    return;
                }

                // 确认创建快照任务
                String taskUuid = bocloudResult.getData().toString();
                VendorTaskMsg taskMsg = smartTransporter.getTask(vendor, taskUuid, context.getTarget());
                if (taskMsg.getSmartFailed()) {
                    operateResult.setSuccess(false);
                    operateResult.setMessage("虚拟卷创建快照失败：" + taskMsg.getSmartFinalErrorMessage());
                    resourceEventPublisher.send(operateResult);
                    return;
                }

                // 确认快照数据
                String snapshotUuid = taskMsg.getTargetUuid();
                SnapshotModel snapshotParamModel = new SnapshotModel();
                snapshotParamModel.setSnapshotType("VOLUME");
                snapshotParamModel.setSnapshotUuid(snapshotUuid);
                bocloudResult = snapshotDriver.detail(vendor.getUuid(), null, snapshotParamModel);
                if (bocloudResult.isFailed()) {
                    operateResult.setSuccess(false);
                    operateResult.setMessage("虚拟卷创建快照失败：" + bocloudResult.getMessage());
                    resourceEventPublisher.send(operateResult);
                    return;
                }
                SnapshotModel snapshotResultModel = (SnapshotModel) bocloudResult.getData();

                // 快照数据入库
                Snapshot snapshot = new Snapshot();
                smartTransporter.convert(snapshotResultModel, snapshot);
                snapshot.setVolumeId(volume.getId());
                snapshot.setVendorId(vendor.getId());
                snapshot.setCreatorId(context.getTarget());
                snapshot.setGmtCreate(new Date());
                snapshotRepository.save(snapshot);

                if(snapshot.getSize()==-1){
                    logger.info("开始同步size");
                    this.addSchedule(snapshotResultModel, vendor, context);
                }

                // 发送给云平台统计队列对云平台重新统计
                JSONObject jsonObject = new JSONObject();
                jsonObject.put(Common.VENDORID, vendor.getId());
                amqpTemplate.convertAndSend("vendor.statistics.queue", jsonObject);

                // 发送异步消息
                operateResult.setSuccess(true);
                operateResult.setMessage("虚拟卷创建快照成功：" + taskMsg.getSmartFinalErrorMessage());
                resourceEventPublisher.send(operateResult);
            } catch (Exception e) {
                operateResult.setSuccess(false);
                operateResult.setMessage("虚拟卷创建快照失败：" + e.getMessage());
                resourceEventPublisher.send(operateResult);
            }
        });
        return new BocloudResult(true, "任务已经下发，正在执行...");
    }

    @Override
    public BocloudResult<List<Volume>> listByStatus(String params, RequestContext context) {
        try {
            JSONObject jsonObject = JSONTools.isJSONObj(params);
            if (null == jsonObject) {
                return new BocloudResult<>(false, "参数异常");
            }
            // 云平台ID
            Long vendorId = jsonObject.getLong("vendorId");
            CloudVendor cloudVendor = cloudVendorRepository.query(vendorId);
            Assert.notNull(cloudVendor, "云平台不存在");
            // 状态
            String status = jsonObject.getString("status");
            List<String> statusList = JSONArray.parseArray(status, String.class);
            Long projectId = context.getProject();
            List<Volume> volumes = volumeRepository.list(vendorId, statusList, null, null, projectId,
                    jsonObject.getString("tenantUuid"), jsonObject.getString("regionId"));
            return new BocloudResult<>(true, volumes, "查询成功");
        } catch (Exception e) {
            logger.error("list volume by status error：", e);
            return new BocloudResult<>(false, "查询失败 :" + e.getMessage());
        }
    }

    @Override
    public BocloudResult<List<Volume>> listByVendor(Long vendorId) {
        try {
            List<Volume> volumes = volumeRepository.listByVendorId(vendorId);
            return new BocloudResult<>(true, volumes, "查询volume成功!");
        } catch (Exception e) {
            logger.error("list volume by status error：", e);
            return new BocloudResult<>(false, "查询volume失败!");
        }
    }

    @Override
    public BocloudResult<List<Volume>> listByImage(Long imageId) {
        try {
            List<Volume> volumes = Lists.newArrayList();
            // List<ImageVolume> imageVolumes =
            // imageVolumeRepository.listByImage(imageId);
            // for (ImageVolume imageVolume : imageVolumes) {
            // Volume volume =
            // volumeRepository.query(imageVolume.getVolumeId());
            // if (volume != null) {
            // volumes.add(volume);
            // }
            // }
            return new BocloudResult<>(true, volumes, "查询volume成功!");
        } catch (Exception e) {
            logger.error("list volume by image id error：", e);
            return new BocloudResult<>(false, "查询volume失败!");
        }
    }

    @Override
    public BocloudResult<String> batchRemove(List<Long> ids, RequestContext context) {
        if (ListTool.isEmpty(ids)) {
            return new BocloudResult<>(false, "没有需要删除的硬盘！");
        }
        try {
            List<BocloudResult> succList = Lists.newArrayList();
            List<BocloudResult> failList = Lists.newArrayList();
            Long vendorId = null;
            for (Long id : ids) {
                Volume volume = volumeRepository.query(id);
                if (null != volume) {
                    if (null == vendorId) {
                        vendorId = volume.getVendorId();
                    }
                    BocloudResult result = remove(id, null, context);
                    if (result.isSuccess()) {
                        succList.add(new BocloudResult<>(true, "【" + volume.getName() + "】删除成功"));
                    } else {
                        failList.add(
                                new BocloudResult<>(false, "【" + volume.getName() + "】删除失败：" + result.getMessage()));
                    }
                }
            }
            CloudVendor vendor = cloudVendorRepository.query(vendorId);
            String operate = vendor.getType().toLowerCase() + ".volume";
            // 删除成功的数量
            int success = succList.size();
            // 删除失败的数量
            int fail = failList.size();
            String content = null;
            if (fail == ids.size()) {
                content = "云硬盘批量删除失败，详情如下：\n";
                for (BocloudResult bocloudResult : failList) {
                    content += bocloudResult.getMessage() + "\n";
                }
                resourceEventPublisher
                        .send(new OperateResult(false, content, operate, MapTools.simpleMap("vendorId", vendor.getId()),
                                OperateResult.OperateCategory.ResourceEvent, context));
            } else {
                content = "云硬盘批量删除成功【" + success + "】个,失败【" + fail + "】个，详情如下：\n";
                for (BocloudResult bocloudResult : succList) {
                    content += bocloudResult.getMessage() + "\n";
                }
                for (BocloudResult bocloudResult : failList) {
                    content += bocloudResult.getMessage() + "\n";
                }
                resourceEventPublisher
                        .send(new OperateResult(true, content, operate, MapTools.simpleMap("vendorId", vendor.getId()),
                                OperateResult.OperateCategory.ResourceEvent, context));
            }
        } catch (Exception e) {
            logger.error("batch remove volume fail:", e);
            return new BocloudResult<>(false, "批量删除任务下发失败");
        }
        return new BocloudResult<>(true, "批量删除任务已下发，正在执行...");
    }

    @Override
    public BocloudResult extend(VolBean volBean, RequestContext context) {
        String path = Volume.class.getSimpleName() + "_" + volBean.getId();
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            Volume volume = volumeRepository.query(volBean.getId());
            if (null == volume) {
                logger.warn("volume does not exist!");
                return new BocloudResult<>(false, "云硬盘不存在!");
            }
            CloudVendor vendor = cloudVendorRepository.query(volume.getVendorId());
            if (null == vendor) {
                logger.warn("Cloud vendor does not exist!");
                return new BocloudResult<>(false, "云平台不存在!");
            }
            Integer oldSize = volume.getSize();
            Integer newSize = volBean.getNewSize();
            if (!CloudProvider.MANAGEONE.name().equalsIgnoreCase(vendor.getType())) {
                if (newSize <= oldSize) {
                    return new BocloudResult<>(false, "新磁盘大小不能小于当前设置!");
                }
            }
            BocloudResult result = new BocloudResult<>(false, "修改失败");
            if (CloudProvider.ALIYUN.name().equalsIgnoreCase(vendor.getType())
                    || CloudProvider.VOLCENGINE.name().equalsIgnoreCase(vendor.getType())) {
                result = volumeDriver.extend(volume.getVolumeUuid(), newSize, volBean.getType(), vendor.getUuid(),
                        volume.getRegionId());
            } else {
                result = volumeDriver.extend(volume.getVolumeUuid(), newSize, vendor.getUuid(), volume.getRegionId());
            }

            if (result.isFailed()) {
                return new BocloudResult<>(false, "修改失败：" + result.getMessage());
            }
            volume.setSize(newSize);
            volume.setMenderId(context.getTarget());
            volume.setGmtModify(new Date());
            volumeRepository.update(volume);
            // 天翼云 阿里云 支持系统盘扩容
            if ((CloudProvider.TIANYI.name().equalsIgnoreCase(vendor.getType())
                || CloudProvider.ALIYUN.name().equalsIgnoreCase(vendor.getType())
                || CloudProvider.HUAWEI.name().equalsIgnoreCase(vendor.getType())
                || CloudProvider.HCSO.name().equalsIgnoreCase(vendor.getType())) && volume.getBootVolume()) {
                CloudServer cloudServer = cloudServerRepository.query(volume.getServerId());
                if (null != cloudServer) {
                    cloudServer.setDisk(newSize);
                    cloudServerRepository.update(cloudServer);
                }
            }
            ResourceEvent resourceEvent = new ResourceEvent(volume.getId(), "云硬盘扩容",
                    "云硬盘 【" + volume.getName() + "】由" + oldSize + "GB扩容到" + newSize + "GB,操作成功！", context.getTarget(),
                    new Date(), "STORAGE", vendor.getId(), context.getCatalog());
            resourceEvent.setResourceName(volume.getName());

            // 硬盘扩容操作记录
            JSONObject operation = new JSONObject();
            operation.put("operation", "STORAGE_EXPANSION");
            operation.put("oldSize", oldSize);
            operation.put("newSize", newSize);
            resourceEvent.setOperation(String.valueOf(operation));
            resourceEventRepository.save(resourceEvent);
            return new BocloudResult<>(true, "云硬盘大小修改成功");
        } catch (Exception e) {
            logger.error("Get error message：", e);
            return new BocloudResult<>(false, "云硬盘大小修改失败");
        }
    }

    public BocloudResult changeVolumeOrderStatus(Volume volume, RequestContext context) {
        try {
            // 修改云主机订单状态
            if (!org.springframework.util.StringUtils.isEmpty(volume.getUuid())) {
                OrderMessage orderMessage = new OrderMessage(volume.getUuid(), Operation.Cancelation,
                        OrderItemStatus.UnsubscribeSuccess, null, null, null, null, new ArrayList<>(),
                        ResourceCategory.Storage.name(), context);
                orderMessage.setCategory(ResourceCategory.Storage.name());
                List<QuotaBean> quotas = new ArrayList<>();
                CloudProvider provider = CloudProvider.valueOf(volume.getVendorType());
                switch (provider) {
                    case HUAWEI:
                    case HCSO:
                        quotas.add(new QuotaBean("huawei.stanadard.cbs", 1));
                        break;
                    case TIANYI:
                        quotas.add(new QuotaBean("tianyi.standard.volume", 1));
                        break;
                    default:
                        break;
                }
                quotas.add(new QuotaBean("meta.disk", volume.getSize()));
                orderMessage.setQuotas(quotas);
                logger.info("云硬盘退订 orderMessage ： " + JSON.toJSONString(orderMessage));
                amqpTemplate.convertAndSend("resource.result.queue", orderMessage);
            }
            return new BocloudResult<>(true, "云硬盘订单状态更新成功");
        } catch (Exception e) {
            logger.error("订单状态更新失败：", e);
            return new BocloudResult<>(true, "订单状态更新失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult<String> uploadToImage(String params, RequestContext context) {
        try {
            JSONObject object = JSONObject.parseObject(params);
            if (null == object) {
                return new BocloudResult<>(false, "参数格式错误");
            }
            Long id = object.getLong("id");
            ImageModel model = new ImageModel();
            model.setName(object.getString("name"));
            model.setForce(object.getBoolean("force"));
            model.setOsType(object.getString("osType"));
            Volume volume = volumeRepository.query(id);
            if (null == volume) {
                logger.error("volume does not exists");
                return new BocloudResult<>(false, "云硬盘不存在");
            }
            CloudVendor vendor = cloudVendorRepository.query(volume.getVendorId());
            if (null == vendor) {
                logger.error("Cloud vendor does not exists");
                return new BocloudResult<>(false, "云平台不存在");
            }
            String status = volume.getStatus();
            volumeRepository.updateStatus(id, "UPLOADING", context.getTarget());
            taskExecutor.execute(() -> {
                String operate = vendor.getType().toLowerCase() + ".image";
                String content = "镜像上传失败";
                try {
                    BocloudResult result = volumeDriver.uploadToImage(volume.getVolumeUuid(), model, vendor.getUuid(),
                            null);
                    if (result.isSuccess()) {
                        content = "镜像上传成功";
                        Image image = JSONObject.parseObject(JSONObject.toJSONString(result.getData()), Image.class);
                        image.preSave(context.getTarget(), context.getTarget(), volume.getVendorId(),
                                context.getTenant(), context.getProject());
                        image.setGmtCreate(new Date());
                        image.setCatalog("VM");
                        imageRepository.save(image);
                    } else {
                        content += "：" + result.getMessage();
                    }
                    volumeRepository.updateStatus(id, status, context.getTarget());
                    resourceEventPublisher.send(new OperateResult(result.isSuccess(), content, operate,
                            MapTools.simpleMap("vendorId", vendor.getId()), OperateResult.OperateCategory.ResourceEvent,
                            context));
                } catch (Exception e) {
                    logger.error("Get error message：", e);
                    resourceEventPublisher.send(
                            new OperateResult(false, content, operate, MapTools.simpleMap("vendorId", vendor.getId()),
                                    OperateResult.OperateCategory.ResourceEvent, context));
                }
            });
            return new BocloudResult<>(true, "上传镜像任务已下发，正在执行...");
        } catch (Exception e) {
            logger.error("Get error message：", e);
            return new BocloudResult<>(false, "镜像上传失败");
        }
    }

    @Override
    public BocloudResult<Integer> count(Long userId, Long projectId, Long tenantId) {
        try {
            List<Param> params = Lists.newArrayList();
            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.volumeRepository.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 attach(Long id, Long serverId, RequestContext context, String mountpoint) {
        String path = Volume.class.getSimpleName() + "_" + id;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            Volume volume = volumeRepository.query(id);
            if (null == volume) {
                logger.warn("volume data not exist");
                return new BocloudResult<>(false, "数据不存在");
            }
            CloudServer server = cloudServerRepository.query(serverId);
            if (null == server) {
                logger.warn("cloud server data not exist");
                return new BocloudResult<>(false, "数据不存在");
            }
            // 云供应商
            CloudVendor vendor = cloudVendorRepository.query(volume.getVendorId());
            if (null == vendor) {
                logger.error("get cloud vendor failure");
                return new BocloudResult<>(false, "所在平台不存在");
            }
            taskExecutor.execute(() -> {
                String operate = vendor.getType().toLowerCase() + ".volume";
                String content = "挂载硬盘失败";
                BocloudResult result = volumeDriver.attachByPoint(vendor.getUuid(), volume.getRegionId(),
                        server.getInstanceId(), volume.getVolumeUuid(), mountpoint);
                if (result.isSuccess()) {
                    // 修改状态
                    volume.setStatus("IN_USE");
                    volume.setServerId(serverId);
                    volume.setInstanceId(server.getInstanceId());
                    volume.setAttachedTime(new Date());
                    volume.setDetachedTime(null);
                    if (CloudProvider.TIANYI.name().equals(server.getVendorType())) {
                        volume.setDevice(mountpoint);
                    } else if (!CloudProvider.ALIYUN.name().equals(server.getVendorType())) {
                        volume.setDevice(result.getData().toString());
                    }
                    try {
                        volumeRepository.update(volume);
                        ResourceEvent resourceEvent = new ResourceEvent(volume.getId(), "云硬盘挂载",
                                "云硬盘 【" + volume.getName() + "】挂载成功！云主机【" + server.getName() + "】", context.getTarget(),
                                new Date(), "STORAGE", vendor.getId(), context.getCatalog());
                        resourceEvent.setResourceName(volume.getName());
                        resourceEventRepository.save(resourceEvent);

                        // 添加云主机操作
                        ResourceEvent serverResourceEvent = new ResourceEvent(serverId, "云硬盘挂载", "挂载成功",
                                context.getTarget(), new Date(), "VM", vendor.getId(), context.getCatalog());
                        resourceEventRepository.save(serverResourceEvent);
                        content = "挂载硬盘成功";
                    } catch (Exception e) {
                        logger.error("volume attach fail : " + e);
                    }
                } else {
                    content = result.getMessage();
                }
                resourceEventPublisher.send(new OperateResult(result.isSuccess(), content, operate,
                        MapTools.simpleMap("vendorId", vendor.getId()), OperateResult.OperateCategory.ResourceEvent,
                        context));
            });
            return new BocloudResult<>(true, volume, "挂载任务已下发，正在执行...");
        } catch (Exception e) {
            logger.error("attach volume to cloud server fail:", e);
            return new BocloudResult<>(false, "挂载硬盘失败");
        }
    }

    @Override
    public BocloudResult<String> onboard(String params, RequestContext context) {
        try {
            JSONObject paramsObject = JSON.parseObject(params);
            Long vendorId = paramsObject.getLong("vendorId");
            Long storageId = paramsObject.getLong("storageId");
            JSONArray volumes = paramsObject.getJSONArray("volumes");

            if (vendorId == null || storageId == null || volumes == null || volumes.size() == 0) {
                logger.error("管理现有镜像失败，参数格式错误");
                return new BocloudResult<>(false, "管理现有存储上的卷失败，参数格式错误");
            }
            CloudVendor vendor = cloudVendorRepository.query(vendorId);
            if (null == vendor) {
                logger.error("get cloud vendor {} failure", vendorId);
                return new BocloudResult<>(false, "管理现有存储上的卷失败，所在平台不存在");
            }
            Storage storage = storageRepository.get(storageId);
            if (storage == null) {
                logger.error("get storage {} failure", storageId);
                return new BocloudResult<>(false, "管理现有存储上的卷失败，所在存储器不存在");
            }

            List<String> volumeIds = new ArrayList<>();
            for (int i = 0; i < volumes.size(); i++) {
                String volumeId = volumes.getJSONObject(i).getString("volumeId");
                volumeIds.add(volumeId);
            }
            new Thread(() -> {
                OperateResult operateResult = new OperateResult(true, "执行成功",
                        vendor.getType().toLowerCase() + ".volume", MapTools.simpleMap("vendorId", vendorId),
                        OperateResult.OperateCategory.ResourceEvent, context);
                try {
                    // 先清空redis，以免下次再查询可供管理卷的时候从redis中获取到脏数据
                    String redisKey = PowervcRedisKeyBuilder.buildForVolume(vendor.getId(), storage.getId());
                    redisTemplate.delete(redisKey);
                    // 开始管理现有卷
                    BocloudResult onboardResult = volumeDriver.onboard(vendor.getUuid(), storage.getHost(), volumeIds);
                    if (onboardResult.isFailed()) {
                        logger.error("管理现有存储上的卷失败，{}", onboardResult);
                        operateResult.setSuccess(false);
                        operateResult.setMessage("管理现有存储上的卷失败:" + onboardResult.getMessage());
                        resourceEventPublisher.send(operateResult);
                        return;
                    }
                    long start = System.currentTimeMillis();
                    int successCnt = 0;
                    while (successCnt < volumes.size()
                            && System.currentTimeMillis() - start < 1000 * 60 * volumes.size()) {
                        BocloudResult listResult = volumeDriver.list(vendor.getUuid(), null);
                        if (listResult.isFailed()) {
                            logger.error("向Powervc下发管理现有卷任务成功，但重新查询Powervc卷列表失败:" + listResult.getMessage());
                            operateResult.setSuccess(false);
                            operateResult
                                    .setMessage("向Powervc下发管理现有卷任务成功，但重新查询Powervc卷列表失败:" + listResult.getMessage());
                            resourceEventPublisher.send(operateResult);
                            return;
                        }
                        @SuppressWarnings("unchecked")
                        List<VolumeModel> models = (List<VolumeModel>) listResult.getData();
                        for (int i = 0; i < volumes.size(); i++) {
                            JSONObject volume = volumes.getJSONObject(i);
                            if (volume.containsKey("success") && volume.getBoolean("success")) {
                                continue;
                            }

                            for (VolumeModel model : models) {
                                // 存储中如果存在错误的卷，则wwn是空的，这里会报空指针，所以增加非空判断
                                // EMC存儲卷也没有wwn,
                                // 所以当wwn为空的时候，还要按照池名称和卷名称检查一下
                                if ((Objects.nonNull(model.getWwn()) && Objects.nonNull(volume.getString("wwn"))
                                        && Objects.equals(model.getWwn(), volume.getString("wwn")))
                                        || (Objects.nonNull(model.getPoolName()) && Objects.nonNull(model.getName())
                                        && Objects.nonNull(volume.getString("poolName"))
                                        && Objects.nonNull(volume.getString("name"))
                                        && Objects.equals(model.getPoolName(), volume.getString("poolName"))
                                        && Objects.equals(model.getName(), volume.getString("name")))) {
                                    volume.put("name", model.getName());
                                    if ("AVAILABLE".equalsIgnoreCase(model.getStatus())
                                            || "IN_USE".equalsIgnoreCase(model.getStatus())
                                            || "BACKING_UP".equalsIgnoreCase(model.getStatus())
                                            || "UNATTACHED".equalsIgnoreCase(model.getStatus())) {
                                        powervcTransportor.insertOrUpdate(vendor, model, context.getTarget());
                                        volume.put("success", true);
                                        successCnt++;
                                        break;
                                    }
                                }
                            }
                        }
                        Thread.sleep(2000);
                    }
                    operateResult.setSuccess(successCnt > 0);
                    operateResult.setMessage("管理现有卷执行结果:" + successCnt + "成功，" + (volumes.size() - successCnt) + "失败");
                    resourceEventPublisher.send(operateResult);
                    return;
                } catch (Exception e) {
                    logger.error("管理现有卷执行失败", e);
                    operateResult.setSuccess(false);
                    operateResult.setMessage("管理现有卷执行失败:" + e.getMessage());
                    resourceEventPublisher.send(operateResult);
                    return;
                }
            }).start();
            return new BocloudResult<>(true, "管理存储器现有卷任务下发成功, 正在执行...");
        } catch (Exception e) {
            logger.error("管理现有卷执行失败", e);
            return new BocloudResult<>(false, "管理现有卷执行失败");
        }
    }

    @Override
    public BocloudResult<String> unmanage(RequestContext context, Long vendorId, Long storageId, List<Long> volumeIds) {
        try {
            CloudVendor vendor = cloudVendorRepository.query(vendorId);
            if (null == vendor) {
                logger.error("get cloud vendor {} failure", vendorId);
                return new BocloudResult<>(false, "取消管理存储上的卷失败，所在平台不存在");
            }
            Storage storage = storageRepository.get(storageId);
            if (storage == null) {
                logger.error("get storage {} failure", storageId);
                return new BocloudResult<>(false, "取消管理存储上的卷失败，所在存储器不存在");
            }
            List<String> volumeIdsStr = Lists.newArrayList();
            if (volumeIds != null) {
                for (Long volumeId : volumeIds) {
                    Volume volume = volumeRepository.query(volumeId);
                    if (volume == null) {
                        logger.error("存储卷{}不存在，无法取消管理", volumeId);
                        return new BocloudResult<>(false, "存储卷[" + volumeId + "]不存在，无法取消管理");
                    }
                    if (!serverVolumeRepository.listByVolumeId(volumeId).isEmpty()) {
                        logger.error("存储卷{}正在被云主机使用，无法取消管理", volume.getName());
                        return new BocloudResult<>(false, "存储卷[" + volume.getName() + "]正在被云主机使用，无法取消管理");
                    }
                    // if
                    // (!imageVolumeRepository.listByVolume(volumeId).isEmpty())
                    // {
                    // logger.error("存储卷{}正在被镜像使用，无法取消管理", volume.getName());
                    // return new BocloudResult<>(false, "存储卷[" + volume.getName()
                    // +
                    // "]正在被云主机使用，无法取消管理");
                    // }
                    if (volume != null && storageId.equals(volume.getStorageId())) {
                        volumeIdsStr.add(volume.getVolumeUuid());
                    }
                }
                // 先清空redis，以免下次再查询可供管理卷的时候从redis中获取到脏数据
                String redisKey = PowervcRedisKeyBuilder.buildForVolume(vendor.getId(), storage.getId());
                redisTemplate.delete(redisKey);
                // 执行取消管理操作
                BocloudResult result = volumeDriver.unmanage(vendor.getUuid(), storage.getHost(), volumeIdsStr);
                if (result.isFailed()) {
                    logger.error("调用powervc取消管理存储卷失败：{}", result);
                    return result;
                }
                volumeIds.forEach(volumeId -> {
                    try {
                        volumeRepository.remove(volumeId, context.getTarget());
                    } catch (Exception e) {
                        logger.error("取消管理现有存储上的卷异常：", e);
                    }
                });
            }
            return new BocloudResult<>(true, "取消管理现有存储上的卷成功");
        } catch (Exception e) {
            logger.error("取消管理现有存储上的卷异常：", e);
            return new BocloudResult<>(false, "取消管理现有存储上的卷失败");
        }
    }

    @Override
    public BocloudResult<List<Volume>> listByStorage(Long storageId) {
        try {
            List<Volume> volumes = volumeRepository.listByStorageId(storageId);
            return new BocloudResult<>(true, volumes, "查询volume成功!");
        } catch (Exception e) {
            logger.error("list volume by status error：", e);
            return new BocloudResult<>(false, "查询volume失败!");
        }
    }

    @Override
    public BocloudResult<List<Volume>> listByTemplate(Long templateId) {
        try {
            List<Volume> volumes = volumeRepository.listByTemplateId(templateId);
            return new BocloudResult<>(true, volumes, "查询volume成功!");
        } catch (Exception e) {
            logger.error("list volume by status error：", e);
            return new BocloudResult<>(false, "查询volume失败!");
        }
    }

    @Override
    public BocloudResult operations(VolBean volBean, RequestContext context) {
        String action = volBean.getAction();
        if ("attach".equals(action)) {
            String mountpoint = volBean.getMountpoint();
            Long serverId = volBean.getServerId();
            if (null == mountpoint || "null".equals(mountpoint)) {
                return this.attach(volBean, context);
            } else {
                return this.attach(volBean.getId(), serverId, context, mountpoint);
            }
        }
        if ("detach".equals(action)) {
            return this.detach(volBean, context);
        }
        if ("extend".equals(action)) {
            return this.extend(volBean, context);
        }
        if ("copy".equals(action)) {
            try {
                if (volBean.getId() == null) {
                    return new BocloudResult<>(false, "参数格式不正确");
                }
                Volume volume = volumeRepository.query(volBean.getId());
                if (volume == null || volume.getDeleted()) {
                    return new BocloudResult<>(false, "存储卷不存在或已被删除");
                }
                CloudVendor vendor = cloudVendorRepository.query(volume.getVendorId());
                if (vendor == null || vendor.getDeleted()) {
                    return new BocloudResult<>(false, "平台不存在或已被删除");
                }
                return applicationContext.getBean(vendor.getType().toLowerCase() + VolumeService.class.getSimpleName(),
                        VolumeService.class).operations(volBean, context);
            } catch (Exception e) {
                logger.error("操作失败：", e);
                return new BocloudResult<>(false, "操作失败：" + e.getMessage());
            }
        }
        if ("snapshot".equals(action)) {
            return this.snapshot(volBean, context);
        }
        return new BocloudResult<>(false, "未知操作！");
    }

    @Override
    public BocloudResult addGroups(Long id, String params, RequestContext context) {
        try {
            if (id == null) {
                return new BocloudResult<>(false, "需要参数id");
            }
            Volume volume = volumeRepository.query(id);
            if (volume == null || volume.getDeleted()) {
                return new BocloudResult<>(false, "未找到卷或该卷已经被删除");
            }
            Storage storage = storageRepository.get(volume.getStorageId());
            if (storage == null || storage.getDeleted()) {
                return new BocloudResult<>(false, "未找到存储或该存储已经被删除");
            }
            CloudVendor cloudVendor = cloudVendorRepository.query(storage.getVendorId());
            if (cloudVendor == null || cloudVendor.getDeleted()) {
                return new BocloudResult<>(false, "未找到平台或该平台已经被删除");
            }
            VolumeService service = applicationContext.getBean(
                    cloudVendor.getType().toLowerCase() + VolumeService.class.getSimpleName(), VolumeService.class);
            return service.addGroups(id, params, context);
        } catch (Exception e) {
            logger.error("卷移入卷组失败：", e);
            return new BocloudResult<>(false, "卷移入卷组失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult removeGroups(Long id, String params, RequestContext context) {
        try {
            if (id == null) {
                return new BocloudResult<>(false, "需要参数id");
            }
            Volume volume = volumeRepository.query(id);
            if (volume == null || volume.getDeleted()) {
                return new BocloudResult<>(false, "未找到卷或该卷已经被删除");
            }
            Storage storage = storageRepository.get(volume.getStorageId());
            if (storage == null || storage.getDeleted()) {
                return new BocloudResult<>(false, "未找到存储或该存储已经被删除");
            }
            CloudVendor cloudVendor = cloudVendorRepository.query(storage.getVendorId());
            if (cloudVendor == null || cloudVendor.getDeleted()) {
                return new BocloudResult<>(false, "未找到平台或该平台已经被删除");
            }
            VolumeService service = applicationContext.getBean(
                    cloudVendor.getType().toLowerCase() + VolumeService.class.getSimpleName(), VolumeService.class);
            return service.removeGroups(id, params, context);
        } catch (Exception e) {
            logger.error("卷移出卷组失败：", e);
            return new BocloudResult<>(false, "卷移出卷组失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult migrateVolume(Volume bean, RequestContext context) {
        try {
            if (bean.getId() == null) {
                return new BocloudResult<>(false, "需要参数id");
            }
            if (bean.getPoolId() == null) {
                return new BocloudResult<>(false, "需要参数poolId");
            }
            Volume volume = volumeRepository.query(bean.getId());
            if (volume == null || volume.getDeleted()) {
                return new BocloudResult<>(false, "未找到存储卷或存储卷已被删除");
            }
            CloudVendor vendor = cloudVendorRepository.query(volume.getVendorId());
            if (vendor == null || vendor.getDeleted()) {
                return new BocloudResult<>(false, "未找到平台或平台已被删除");
            }
            VolumePool pool = volumePoolRepository.get(bean.getPoolId());
            if (pool == null || pool.getDeleted()) {
                return new BocloudResult<>(false, "未找到存储池或存储池已被删除");
            }
            VolumeService service = applicationContext
                    .getBean(vendor.getType().toLowerCase() + VolumeService.class.getSimpleName(), VolumeService.class);
            return service.migrateVolume(bean, context);
        } catch (Exception e) {
            logger.error("卷迁移失败：", e);
            return new BocloudResult<>(false, "卷迁移失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult<GridBean> listByHost(Integer page, Integer rows, Long hostId, Map<String, Object> paramMap,
                                              Map<String, String> sorter) {
        try {
            List<Volume> volumes = volumeRepository.listByHost(page, rows, hostId, paramMap, sorter);
            int total = volumeRepository.countByHost(hostId, paramMap);
            GridBean gridBean = new GridBean(page, rows, total, volumes);
            return new BocloudResult<>(true, gridBean, "查询详情成功");
        } catch (Exception e) {
            logger.error("get volumes fail:", e);
            return new BocloudResult<>(false, "查询详情失败", "", "");
        }
    }

    @Override
    public BocloudResult<GridBean> listInSyncedSet(Integer page, Integer rows, Map<String, Object> paramMap,
                                                   Map<String, String> sorter) {
        try {
            if (null == sorter) {
                sorter = Maps.newHashMap();
            }
            sorter.put("gmtCreate", Common.ONE);
            List<Volume> list = volumeRepository.listInSyncedSet(page, rows, paramMap, sorter);
            int total = volumeRepository.countListInSyncedSet(paramMap);
            GridBean gridBean = new GridBean(page, rows, total, list);
            return new BocloudResult<>(true, gridBean, "查询成功");
        } catch (Exception e) {
            logger.error("Get error message：", e);
            return new BocloudResult<>(false, "查询失败");
        }
    }

    @Override
    public BocloudResult<GridBean> listNotInSyncedSet(Integer page, Integer rows, Map<String, Object> paramMap,
                                                      Map<String, String> sorter) {
        try {
            if (null == sorter) {
                sorter = Maps.newHashMap();
            }
            sorter.put("gmtCreate", Common.ONE);
            List<Volume> list = volumeRepository.listNotInSyncedSet(page, rows, paramMap, sorter);
            int total = volumeRepository.countListNotInSyncedSet(paramMap);
            GridBean gridBean = new GridBean(page, rows, total, list);
            return new BocloudResult<>(true, gridBean, "查询成功");
        } catch (Exception e) {
            logger.error("Get error message：", e);
            return new BocloudResult<>(false, "查询失败");
        }
    }

    @Override
    public BocloudResult<GridBean> listForPowervcVMCreate(int page, int rows, String keyword, long vendorId) {
        try {
            List<Volume> volumes = volumeRepository.listForPowervcVMCreate(page, rows, keyword, vendorId);
            int total = volumeRepository.countForPowervcVMCreate(keyword, vendorId);
            GridBean gridBean = new GridBean(page, rows, total, volumes);
            return new BocloudResult<>(true, gridBean, "查询volume成功!");
        } catch (Exception e) {
            logger.error("list volume by status error：", e);
            return new BocloudResult<>(false, "查询volume失败!");
        }
    }

    @Override
    public BocloudResult<GridBean> listForPowervcVMAttach(int page, int rows, String keyword, long vendorId,
                                                          long vmId) {
        try {
            List<Volume> volumes = volumeRepository.listForPowervcVMAttach(page, rows, keyword, vendorId, vmId);
            int total = volumeRepository.countForPowervcVMAttach(keyword, vendorId, vmId);
            GridBean gridBean = new GridBean(page, rows, total, volumes);
            return new BocloudResult<>(true, gridBean, "查询volume成功!");
        } catch (Exception e) {
            logger.error("list volume by status error：", e);
            return new BocloudResult<>(false, "查询volume失败!");
        }
    }

    @Override
    public BocloudResult<GridBean> listForPowervcImageCreate(int page, int rows, String keyword, long vendorId) {
        try {
            List<Volume> volumes = volumeRepository.listForPowervcImageCreate(page, rows, keyword, vendorId);
            int total = volumeRepository.countForPowervcImageCreate(keyword, vendorId);
            GridBean gridBean = new GridBean(page, rows, total, volumes);
            return new BocloudResult<>(true, gridBean, "查询volume成功!");
        } catch (Exception e) {
            logger.error("list volume by status error：", e);
            return new BocloudResult<>(false, "查询volume失败!");
        }
    }

    @Override
    public BocloudResult<String> apply(ApplicationParam param) {
        try {
            Assert.notNull(param, "参数格式错误");
            ServiceOrder order = param.getOrder();
            Assert.notNull(order, "订单不存在");
            List<OrderItem> items = order.getItems();
            Assert.notEmpty(items, "订单明细不存在");
            // 申请人
            RequestContext context = param.getContext();
            Assert.notNull(context, "申请人不存在");
            // 位置
            LocationModel location = param.getLocation();
            // 订购信息
            EmptionModel emption = param.getEmption();
            // 使用时长信息
            DurationModel duration = emption.getDuration();
            // 使用时长单位Hour/Month
            DurationModel.Mode mode = duration.getMode();
            // 时长
            Integer month = duration.getAmount();
            // 申请个数
            Integer count = null == emption.getCount() ? 1 : emption.getCount();
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(new Date());
            if (DurationModel.Mode.Hour == mode) {
                calendar.setTime(DateTools.stringToDateTime("2099-12-31 00:00:00"));
            } else {
                calendar.add(Calendar.MONTH, month);
            }
            CloudVendor vendor = cloudVendorRepository.query(location.getVendorId());
            Assert.notNull(vendor, "当前可用域未绑定云平台");
            CloudProvider provider = CloudProvider.valueOf(vendor.getType());
            // 配置信息
            JSONObject configs = param.getConfigs();
            // 名称
            String name = configs.getString("name");
            // 域
            String region = configs.getString("region");
            // 大小
            Integer size = configs.getInteger("size");
            String regionId = configs.getString(Common.REGIONID);
            if (StringUtils.isEmpty(regionId)) {
                regionId = location.getRegion();
            }
            String zone = configs.getString("zoneId");
            if (StringUtils.isEmpty(zone)) {
                zone = location.getAz();
            }
            String remark = configs.getString("remark");
            String resourceLabel = configs.getString("resourceLabel");
            Long snapshotId = configs.getLong("snapshotId");
            if (CloudProvider.OPENSTACK == provider||CloudProvider.EASYSTACK == provider) {
                OSTenant osTenant = osTenantRepository.getByTenantId(context.getTenant(), vendor.getId());
                Assert.notNull(osTenant, "租户云平台认证信息不存在");
            }
            // 创建成功的云硬盘
            List<BocloudResult> succList = Lists.newArrayList();
            // 创建失败的云硬盘
            List<BocloudResult> failList = Lists.newArrayList();
            List<Future<BocloudResult<Volume>>> futures = new ArrayList<>();
            logger.info("apply volume 【" + name + "】 start...");
            for (int i = 0; i < count; i++) {
                VolumeModel model = new VolumeModel();
                model.setSize(size);
                model.setName(name + "_" + UUID.randomUUID().toString());
                if (CloudProvider.AZURE.name().equalsIgnoreCase(vendor.getType())) {
                    // 和自服务别的逻辑有冲突
                    // model.setCategory(configs.getString("category"));
                    model.setCategory(configs.getString("azurecategory"));
                    model.setResourceGroupName(configs.getString("azureResourceGroupName"));
                    model.setRegionId(regionId);
                    futures.add(taskExecutor
                            .submit(new PublicCloudVolumeBuilder(volumeDriver, model, regionId, vendor, context)));
                } else if (CloudProvider.FUSIONCLOUD.name().equals(vendor.getType())) {
                    Region reginInfo = regionRepository.query(Long.parseLong(regionId));
                    if (reginInfo == null) {
                        futures.add(taskExecutor.submit(() -> new BocloudResult<>(false, "区域未找到")));
                    } else {
                        model.setZone(reginInfo.getCode());
                        model.setRemark(remark);
                        futures.add(taskExecutor.submit(
                                new FusionCloudVolumeBuilder(volumeDriver, model, "", vendor, regionId, context)));
                    }
                } else if (CloudProvider.MANAGEONE.name().equals(vendor.getType())) {
                    model.setZone(region);
                    model.setRemark(remark);
                    futures.add(taskExecutor.submit(new ManageOneVolumeBuilder(volumeDriver, model, "", vendor, region,
                            context, accountService)));
                } else if (CloudProvider.HUAWEI.name().equals(vendor.getType())
                        || CloudProvider.HCSO.name().equals(vendor.getType())
                        || CloudProvider.TENCENT.name().equals(vendor.getType())
                        || CloudProvider.QCLOUD.name().equals(vendor.getType())
                        || CloudProvider.ALIYUN.name().equals(vendor.getType())) {
                    model.setZone(zone);
                    model.setRegionId(regionId);
                    model.setRemark(remark);
                    Snapshot snapshot = snapshotRepository.query(snapshotId);
                    if (null != snapshot) {
                        model.setSourceSnapUuid(snapshot.getSnapshotUuid());
                    }
                    model.setType(configs.getString("diskType"));
                    model.setVolumeType(configs.getString("diskType"));
                    model.setCategory(configs.getString("diskType"));
                    logger.info("apply volume param : " + JSON.toJSONString(model));
                    futures.add(taskExecutor
                            .submit(new PublicCloudVolumeBuilder(volumeDriver, model, regionId, vendor, context)));
                } else if (CloudProvider.OPENSTACK.name().equalsIgnoreCase(vendor.getType())||CloudProvider.EASYSTACK.name().equalsIgnoreCase(vendor.getType())) {
                    Long sourceImgId = configs.getLong("sourceImgId");
                    if (null != sourceImgId && 0L != sourceImgId) {
                        Image image = imageRepository.query(sourceImgId);
                        if (null == image) {
                            return new BocloudResult<>(false, "源为镜像时已选择的镜像不存在");
                        }
                        model.setImageUuid(image.getImageUuid());
                    }
                    Long sourceSnapId = configs.getLong("sourceSnapId");
                    if (null != sourceSnapId && 0L != sourceSnapId) {
                        Snapshot snapshot = snapshotRepository.query(sourceSnapId);
                        if (null == snapshot) {
                            return new BocloudResult<>(false, "源为快照时已选择的快照不存在");
                        }
                        Volume volume = volumeRepository.query(snapshot.getVolumeId());
                        if (null == volume) {
                            return new BocloudResult<>(false, "源为快照时已选择的快照关联卷不存在");
                        }
                        if (null != volume.getBootVolume() && volume.getBootVolume()) {
                            model.setBootVolume(true);
                        } else {
                            model.setBootVolume(false);
                        }
                        model.setSourceSnapUuid(snapshot.getSnapshotUuid());
                    }
                    Long sourceValidId = configs.getLong("sourceValidId");
                    if (null != sourceValidId && 0L != sourceValidId) {
                        Volume volume = volumeRepository.query(sourceValidId);
                        if (null == volume) {
                            return new BocloudResult<>(false, "源为卷时已选择的卷不存在");
                        }
                        model.setSourceVolidUuid(volume.getVolumeUuid());
                    }
                    Long volumeTypeId = configs.getLong("volumeTypeId");
                    if (null != volumeTypeId && 0L != volumeTypeId) {
                        VolumeType volumeType = volumeTypeRepository.query(volumeTypeId);
                        if (null == volumeType) {
                            return new BocloudResult<>(false, "卷类型不存在");
                        }
                        model.setVolumeType(volumeType.getVolumeTypeUuid());
                    }
                    futures.add(taskExecutor.submit(new OSVolumeBuilder(volumeDriver, model, "", vendor, region,
                            context, osTenantRepository)));
                } else if (CloudProvider.TCE.name().equalsIgnoreCase(vendor.getType())) {
                    model.setRemark(remark);
                    model.setName(name + "_" + IDFactory.instance().uuid());
                    model.setSize(size);
                    model.setRegionId(regionId);
                    model.setDiskChargeType("POSTPAID_BY_HOUR");
                    model.setType(configs.getString("diskType"));
                    model.setZone(zone);
                    model.setRegionId(regionId);
                    Thread.sleep(1000);
                    futures.add(taskExecutor
                            .submit(new TceVolumeBuilder(volumeDriver, model, "", vendor, region, context)));
                } else if (CloudProvider.AWS.name().equalsIgnoreCase(vendor.getType())) {
                    String category = configs.getString("diskType");
                    model.setZone(zone);
                    model.setCategory(category);
                    Long awsSourceSnapId = configs.getLong("sourceSnapId");
                    try {
                        Snapshot awsSnapshot = snapshotRepository.query(awsSourceSnapId);
                        if (null != awsSnapshot) {
                            model.setSourceSnapshotId(awsSnapshot.getSnapshotUuid());
                        }
                    } catch (Exception e) {
                        logger.error("快照查询失败：" + e.getMessage());
                    }
                    if ("io1".equals(category)) {
                        Integer iops = configs.getInteger("iops");
                        model.setIops(iops);
                    }
                    futures.add(taskExecutor
                            .submit(new PublicCloudVolumeBuilder(volumeDriver, model, regionId, vendor, context)));
                } else if (CloudProvider.SMARTX.name().equalsIgnoreCase(vendor.getType())) {
                    model.setType(configs.getString("disktype"));
                    if ("空白卷".equals(configs.getString("disktype"))) {
                        BocloudResult<ServiceCategory> categoryResult = cosInternalService.getCategory(configs.getLong("categoryId"));
                        if (categoryResult.isFailed()) {
                            return new BocloudResult<>(false, "查询规格信息失败：" + categoryResult.getMessage());
                        }
                        ServiceCategory serviceCategory = categoryResult.getData();
                        model.setMultiattach("SMARTX-SHARE".equals(serviceCategory.getCode()));
                        model.setBlockSize(1D);
                        model.setBlockCount(size * 1024L * 1024L * 1024L);
                        List<VolumeTemplate> volumeTemplates = volumeTemplateRepository.listByVendor(location.getVendorId());
                        if (CollectionUtils.isEmpty(volumeTemplates)) {
                            return new BocloudResult<>(false, "未找到合适的存储策略!");
                        }
                        VolumeTemplate volumeTemplate = volumeTemplates.stream()
                                .filter(vt -> "default".equals(vt.getName())).findFirst()
                                .orElse(volumeTemplates.get(0));
                        model.setVolumeTemplateId(volumeTemplate.getId());
                        model.setVolumeTemplateUuid(volumeTemplate.getUuid());
                        model.setRemark(remark);
                    } else if ("卷".equals(configs.getString("disktype"))) {
                        Long sourceValidId = configs.getLong("sourceValidId");
                        Volume volume = volumeRepository.query(sourceValidId);
                        if (volume == null) {
                            return new BocloudResult<>(false, "未找到id为" + sourceValidId + "的源卷");
                        }
                        model.setVolumeUuid(volume.getVolumeUuid());
                        model.setRemark(remark);
                    } else if ("快照".equals(configs.getString("disktype"))) {
                        Long sourceSnapId = configs.getLong("sourceSnapId");
                        Snapshot snapshot = snapshotRepository.query(sourceSnapId);
                        if (snapshot == null) {
                            return new BocloudResult<>(false, "未找到id为" + snapshot + "的快照");
                        }
                        model.setSnapshotUuid(snapshot.getSnapshotUuid());
                        model.setRemark(remark);
                    }
                    futures.add(taskExecutor.submit(new SmartVolumeBuilder(smartTransporter, volumeDriver,
                            snapshotDriver, volumeTemplateRepository, vendor, model, context)));
                } else if (CloudProvider.FUSIONSPHERE.name().equalsIgnoreCase(vendor.getType())) {
                    //根据可用域查询数据存储
                    PoolGroup poolGroup = poolGroupRepository.query(location.getPoolGroupId());
                    Assert.notNull(poolGroup, "资源池不存在");
                    List<PoolGroupRelation> poolGroupRelations = poolGroupRelationRepository.list(poolGroup.getId(), "Storage");
                    if (ListTool.isEmpty(poolGroupRelations)) {
                        throw new Exception("此可用域下没有可用的数据存储，请更换可用域");
                    }
                    List<DataStore> dataStores = new ArrayList<>();
                    for (PoolGroupRelation poolGroupRelation : poolGroupRelations) {
                        DataStore dataStore = dataStoreRepository.query(poolGroupRelation.getTarget());
                        dataStores.add(dataStore);
                    }
                    //选择数据存储
                    List<DataStore> dataStoreList = dataStores.stream().filter(dataStore -> dataStore.getFreeSpace() > size).collect(Collectors.toList());
                    if (ListTool.isEmpty(dataStoreList)) {
                        throw new Exception("此可用域下数据存储可用不足，请更换可用域");
                    }
                    model.setDataStoreUuid(dataStoreList.get(0).getStoreVal());
                    model.setDataStoreId(dataStoreList.get(0).getId());
                    Vdc vdc = vdcRepository.query(dataStoreList.get(0).getVdcId());
                    Assert.notNull(vdc, "站点不存在");
                    model.setVdcUri(vdc.getUri());
                    model.setVdcId(vdc.getId());
                    if ("2".equals(configs.getString("diskType"))) { //精简模式
                        model.setThinlyProvisioned(true);
                    } else {
                        model.setVolumeType(configs.getString("diskType"));
                    }
                    JSONObject diskCategory = configs.getJSONObject("diskCategory");
                    model.setPersistentDisk(diskCategory.getBoolean("persistentDisk"));
                    model.setIndepDisk(diskCategory.getBoolean("indepDisk"));
                    model.setType(configs.getString("type"));
                    Thread.sleep(1000);
                    futures.add(taskExecutor
                            .submit(new FusionSphereVolumeBuilder(volumeDriver, model, vendor, context, region)));

                }
            }
            try {
                for (int i = 0; i < futures.size(); i++) {
                    Future<BocloudResult<Volume>> future = futures.get(i);
                    List<ResourceModel> resources = new ArrayList<>();
                    OrderItem item = items.get(i);
                    // 通知订单
                    OrderMessage message = null;
                    BocloudResult<Volume> result = future.get(30, TimeUnit.MINUTES);
                    Volume volume = result.getData();
                    if (result.isSuccess()) {
                        volume.setBootVolume(false);
                        if (!CloudProvider.OPENSTACK.name().equalsIgnoreCase(vendor.getType())&&!CloudProvider.EASYSTACK.name().equalsIgnoreCase(vendor.getType())) {
                            volume.setRegion(regionId);
                            volume.setRegionId(regionId);
                            volume.setZone(zone);
                        }
                        volume.setCatalog(context.getCatalog());
                        volume.setSkuId(configs.getLong("skuId"));
                        volume.setCategoryId(configs.getLong("categoryId"));
                        volume.setUuid(item.getSn());
                        volume.setRemark(remark);
                        volume.setCreateTime(new Date());
                        volume.setDiskExpireTime(calendar.getTime());
                        // 自服务申请需要用到
                        volume.setCreatorId(location.getCreatorId() == null ? 0 : location.getCreatorId());
                        volume.setOwnerId(location.getOwnerId() == null ? 0 : location.getOwnerId());
                        volume.setMenderId(location.getMenderId() == null ? 0 : location.getMenderId());
                        volume.setCatalog(context.getCatalog());
                        volume.setTenantId(context.getTenant() == null ? 0 : context.getTenant());
                        volume.setBusinessId(location.getBusinessId() == null ? 0 : location.getBusinessId());
                        volume.setProjectId(location.getProjectId() == null ? 0 : location.getProjectId());
                        volume.setExpiredTime(calendar.getTime());
                        volume.setResourceLabel(resourceLabel);
                        // 保存磁盘记录
                        volumeRepository.save(volume);
                        fusionSphereResourceUtils.modifyDataStore(volume.getDataStoreId(), volume.getSize(), "add");
                        ResourceEvent resourceEvent = new ResourceEvent(volume.getId(), "云硬盘申请",
                                "云硬盘 【" + volume.getName() + "】申请成功！", context.getTarget(), new Date(),
                                ResourceCategory.Storage.name(), vendor.getId(), context.getCatalog());
                        resourceEvent.setResourceName(volume.getName());
                        resourceEventRepository.save(resourceEvent);

                        Long serverId = configs.getLong("serverId");
                        if ((CloudProvider.OPENSTACK.name().equalsIgnoreCase(vendor.getType())
                                || CloudProvider.EASYSTACK.name().equalsIgnoreCase(vendor.getType())
                                || CloudProvider.ALIYUN.name().equalsIgnoreCase(vendor.getType())) && null != serverId
                                && 0L != serverId) {
                            VolBean volBean = new VolBean();
                            volBean.setId(volume.getId());
                            volBean.setServerId(serverId);
                            attach(volBean, context);
                        }
                        BocloudResult bocloudResult = new BocloudResult<>(true,
                                "【" + volume.getName() + "】创建成功【" + result.getMessage() + "】");
                        succList.add(bocloudResult);
                        resources.add(new ResourceModel(volume.getName(), volume.getVolumeUuid(), param.getService(),
                                volume.getVolumeUuid(), volume.getUuid()));
                        message = new OrderMessage(item.getSn(), Operation.Application, OrderItemStatus.OpenedSuccess,
                                null, bocloudResult.getMessage(), volume.getGmtCreate(), calendar.getTime(), resources,
                                ResourceCategory.Storage.name(), context);
                    } else {
                        BocloudResult bocloudResult = new BocloudResult<>(false,
                                "【" + volume.getName() + "】创建失败【" + result.getMessage() + "】");
                        failList.add(bocloudResult);
                        message = new OrderMessage(item.getSn(), Operation.Application, OrderItemStatus.OpenedFailure,
                                null, result.getMessage(), null, null, resources, ResourceCategory.Storage.name(),
                                context);
                        message.setQuotas(param.getQuotas());
                    }
                    message.setCategory(ResourceCategory.Storage.name());
                    // 通知订单
                    amqpTemplate.convertAndSend("resource.result.queue", message);

                    if (!StringUtils.isEmpty(param.getCallback())) {
                        BocloudResult bocloudResult = new BocloudResult<>(result.isSuccess(), volume,
                                result.getMessage());
                        this.amqpTemplate.convertAndSend(param.getCallback(), JSONObject.toJSON(bocloudResult));
                    }
                }
            } catch (Exception e) {
                logger.error("apply volume fail:", e);
            }
            // 发送给云平台统计队列对云平台重新统计
            JSONObject jsonObject = new JSONObject();
            jsonObject.put(Common.VENDORID, vendor.getId());
            amqpTemplate.convertAndSend("vendor.statistics.queue", jsonObject);
            logger.info("apply volume 【" + name + "】 end...");
            return new BocloudResult<>(true, "云硬盘申请成功");
        } catch (Exception e) {
            logger.error("Apply volume error：{}", e);
            return new BocloudResult<>(false, e.getMessage());
        }
    }

    @Override
    public BocloudResult alteration(AlterationParam param) {
        try {
            RequestContext context = param.getContext();
            Volume volume = volumeRepository.getByUuid(param.getInstance());
            Assert.notNull(volume, "云硬盘不存在");
            CloudVendor vendor = cloudVendorRepository.query(volume.getVendorId());
            Assert.notNull(vendor, "云平台不存在");
            CloudProvider provider = CloudProvider.valueOf(vendor.getType());
            BocloudResult result = null;
            switch (provider) {
                case MANAGEONE:
                    ManageOneAccount account = accountService.queryAccount(vendor.getId(), context.getTenant());
                    Assert.notNull(account, "认证失败！");
                    result = volumeDriver.extend(volume.getVolumeUuid(), param.getNewDiskSize(), vendor.getUuid(),
                            account.getUsername(), account.getPassword(), account.getProjectId(), account.getDomainName());
                    break;
                case FUSIONSPHERE:
                    VolumeModel modelFS = new VolumeModel();
                    modelFS.setUri(volume.getUri());
                    modelFS.setSize(param.getNewDiskSize());
                    result = volumeDriver.modify(vendor.getUuid(), null, modelFS);
                    break;
                case SMARTX:
                    VolumeModel modelSX = new VolumeModel();
                    modelSX.setName(volume.getName());
                    modelSX.setBlockCount(param.getNewDiskSize() * 1024L * 1024L * 1024L);
                    modelSX.setRemark(volume.getRemark());
                    modelSX.setVolumeUuid(volume.getVolumeUuid());
                    result = volumeDriver.modify(vendor.getUuid(), null, modelSX);
                    break;
                case AWS:
                    VolumeModel model = new VolumeModel();
                    model.setSize(param.getNewDiskSize());
                    model.setVolumeUuid(volume.getVolumeUuid());
                    model.setName(volume.getName());
                    if ("io1".equalsIgnoreCase(volume.getCategory())) {
                        if (param.getNewDiskSize() * 50 < volume.getIops()) {
                            return new BocloudResult(false, "IOPS 和卷大小之间的最大比率为 50:1");
                        }
                        model.setIops(volume.getIops());
                    }
                    result = volumeDriver.modify(vendor.getUuid(), volume.getRegionId(), model);
                    break;
                default:
                	// 默认
                	result = volumeDriver.extend(volume.getVolumeUuid(), param.getNewDiskSize(), vendor.getUuid(), volume.getRegionId());
                    break;
            }
            Assert.isTrue(result.isSuccess(), result.getMessage());
            volume.setSize(param.getNewDiskSize());
            List<ElementModel> upgrade = param.getUpgrade();
            if (!ListTool.isEmpty(upgrade)) {
                Long skuId = upgrade.get(0).getSkuId();
                if (null != skuId) {
                    volume.setSkuId(skuId);
                }
            }
            volumeRepository.update(volume);
            // 天翼云 阿里云 支持系统盘扩容
			if ((CloudProvider.TIANYI.name().equalsIgnoreCase(vendor.getType())
					|| CloudProvider.ALIYUN.name().equalsIgnoreCase(vendor.getType())) && volume.getBootVolume()) {
				CloudServer cloudServer = cloudServerRepository.query(volume.getServerId());
				if (null != cloudServer) {
					cloudServer.setDisk(param.getNewDiskSize());
					cloudServerRepository.update(cloudServer);
				}
			}
            OrderMessage message = new OrderMessage();
            message.setSn(param.getInstance());
            message.setNewSn(param.getInstance());
            message.setOperation(Operation.Upgrade);
            message.setStatus(OrderItemStatus.ChangeSuccess);
            message.setCategory(ResourceCategory.Storage.name());
            message.setMessage("云硬盘变更成功");
            message.setContext(context);
            logger.info("云硬盘变更成功通知cos ： " + JSON.toJSONString(message));
            amqpTemplate.convertAndSend("resource.result.queue", message);
            return new BocloudResult<>(true, "云硬盘变更成功");
        } catch (Exception e) {
            logger.error("Get error message：{}", e);
            return new BocloudResult<>(false, e.getMessage());
        }
    }

    @Override
    public BocloudResult extension(ExtensionParam param) {
        try {
            Volume volume = volumeRepository.getByUuid(param.getInstance());
            Assert.notNull(volume, "云硬盘不存在");

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

            OrderMessage message = new OrderMessage();
            message.setSn(param.getInstance());
            message.setOperation(Operation.Extension);
            message.setStatus(OrderItemStatus.ExtensionSuccess);
            message.setExtension(param.getExtension());
            message.setExpiredTime(calendar.getTime());
            message.setCategory(ResourceCategory.Storage.name());
            message.setMessage("云硬盘延期成功");
            amqpTemplate.convertAndSend("resource.result.queue", message);
            return new BocloudResult<>(true, "云硬盘延期成功");
        } catch (Exception e) {
            logger.error("Get error message：{}", e);
            return new BocloudResult<>(false, e.getMessage());
        }
    }

    @Override
    public BocloudResult cancelation(CancelationParam param) {
        try {
            Volume volume = volumeRepository.getByUuid(param.getInstance());
            Assert.notNull(volume, "云硬盘不存在");
            CloudVendor vendor = cloudVendorRepository.query(volume.getVendorId());
            Assert.notNull(vendor, "云平台不存在！");
            RequestContext context = param.getContext();
            BocloudResult result = this.remove(volume.getId(), null, context);
            Assert.isTrue(result.isSuccess(), result.getMessage());
            OrderMessage orderMessage = new OrderMessage(param.getInstance(), Operation.Cancelation,
                    OrderItemStatus.UnsubscribeSuccess, null, "云硬盘退订成功", null, null, new ArrayList<>(),
                    ResourceCategory.Storage.name(), context);
            orderMessage.setCategory(ResourceCategory.Storage.name());
            List<QuotaBean> quotas = new ArrayList<>();
            CloudProvider provider = CloudProvider.valueOf(vendor.getType());
            switch (provider) {
                case OPENSTACK:
                case EASYSTACK:
                case TCE:
                case TENCENT:
                case HUAWEI:
                case HCSO:
                case ALIYUN:
                case MANAGEONE:
                case AZURE:
                case AWS:
                default:
                    quotas.add(new QuotaBean(vendor.getType().toLowerCase() + ".standard.volume", 1));
                    break;
            }
            quotas.add(new QuotaBean("meta.disk", volume.getSize()));
            orderMessage.setQuotas(quotas);
            amqpTemplate.convertAndSend("resource.result.queue", orderMessage);
            return new BocloudResult<>(true, "云硬盘退订成功");
        } catch (Exception e) {
            logger.error("Get error message：{}", e);
            return new BocloudResult<>(false, e.getMessage());
        }
    }

    @Override
    public BocloudResult<List<Volume>> listByCondition(JSONObject object, RequestContext context) {
        try {
            List<Volume> volumes = volumeRepository.listByCondition(object.getLong("vendorId"), object.getLong("vdcId"),
                    object.getLong("clusterId"));
            return new BocloudResult<>(true, volumes, "查询成功");
        } catch (Exception e) {
            logger.error("Get error message：{}", e.getMessage());
            return new BocloudResult<>(false, e.getMessage());
        }
    }

    @Override
    public BocloudResult<List<Volume>> listByVmId(JSONObject object) {
        try {
            List<Volume> volumes = volumeRepository.listByServerId(object.getLong("serverId"));
            return new BocloudResult<>(true, volumes, "查询成功");
        } catch (Exception e) {
            logger.error("Get error message：{}", e);
            return new BocloudResult<>(false, e.getMessage());
        }
    }

    @Override
    public BocloudResult<List<Volume>> listDataDisks(JSONObject object) {
        try {
            List<Volume> volumes = volumeRepository.listByServerId(object.getLong("serverId"));
            List<Volume> filterVolumes = new ArrayList<>();
            for (Volume volume : volumes) {
                if (!"Hard disk 1".equalsIgnoreCase(volume.getName()) || !"硬盘 1".equalsIgnoreCase(volume.getName())) {
                    filterVolumes.add(volume);
                }
            }
            return new BocloudResult<>(true, filterVolumes, "查询成功");
        } catch (Exception e) {
            logger.error("Get error message：{}", e);
            return new BocloudResult<>(false, e.getMessage());
        }
    }

    @Override
    public BocloudResult createOsVolume(JSONObject param, RequestContext context) {
        // 位置
        JSONObject location = param.getJSONObject("location");
        // 配置信息
        JSONObject configs = param.getJSONObject("configs");
        // 名称
        String name = configs.getString("name");
        // 域
        String region = configs.getString("region");
        // 大小
        Integer size = configs.getInteger("size");
        String remark = configs.getString("remark");
        Long serverId = param.getLong("serverId");
        String resourceLabel = param.getString("resourceLabel");
        try {
            CloudVendor vendor = cloudVendorRepository.query(location.getLong("vendorId"));
            Assert.notNull(vendor, "当前可用域未绑定云平台");
            logger.info("apply volume 【" + name + "】 start...");
            VolumeModel model = new VolumeModel();
            model.setSize(size);
            model.setName(name + "_" + UUID.randomUUID().toString());
            VolumeBuilder builder = new OSVolumeBuilder(volumeDriver, model, "", vendor, region, context,
                    osTenantRepository);
            BocloudResult<Volume> result = builder.build();
            Volume volume = result.getData();
            if (result.isSuccess()) {
                volume.setRemark(remark);
                volume.setResourceLabel(resourceLabel);
                // 保存磁盘记录
                volumeRepository.save(volume);
                ResourceEvent resourceEvent = new ResourceEvent(volume.getId(), "云硬盘申请",
                        "云硬盘 【" + volume.getName() + "】申请成功！", context.getTarget(), new Date(),
                        ResourceCategory.Storage.name(), vendor.getId(), context.getCatalog());
                resourceEvent.setResourceName(volume.getName());
                resourceEventRepository.save(resourceEvent);
                if (null != serverId && 0L != serverId) {
                    VolBean volBean = new VolBean();
                    volBean.setId(volume.getId());
                    volBean.setServerId(serverId);
                    attach(volBean, context);
                }
                // 发送给云平台统计队列对云平台重新统计
                JSONObject jsonObject = new JSONObject();
                jsonObject.put(Common.VENDORID, vendor.getId());
                amqpTemplate.convertAndSend("vendor.statistics.queue", jsonObject);
                logger.info("apply volume 【" + name + "】 end...");
            }
            return new BocloudResult<>(true, volume, "云硬盘申请成功");
        } catch (Exception e) {
            logger.error("apply volume fail:", e);
            return new BocloudResult<>(false, e.getMessage());
        }
    }

    @Override
    public BocloudResult<Object> listBackupResources(String params, RequestContext context) {
        try {
            JSONObject object = JSONTools.isJSONObj(params);
            Long vendorId = object.getLong("vendorId");
            String regionId = object.getString("regionId");
            String type = object.getString("type");
            if (null == regionId) {
                return new BocloudResult<>(false, "参数格式错误");
            }
            CloudVendor cloudVendor = cloudVendorRepository.query(vendorId);
            if (null == cloudVendor) {
                return new BocloudResult<>(false, "平台认证失败！");
            }
            if ("disk".equalsIgnoreCase(type)) {
                return new BocloudResult<>(true, volumeRepository.listBackupResources(vendorId, regionId), "查询成功");
            } else {
                return new BocloudResult<>(true, cloudServerRepository.listBackupResources(vendorId, regionId), "查询成功");
            }
        } catch (Exception e) {
            logger.error("Get error message：", e);
            return new BocloudResult<>(false, "查询失败");
        }
    }

    @Override
    public BocloudResult<GridBean<Snapshot>> listSnapshotById(Long id, Pager pager) {
        List<Snapshot> list = snapshotRepository.listByVolumeId(id, pager);
        Integer count = snapshotRepository.countByVolumeId(id, pager.getParams());
        GridBean<Snapshot> gridBean = new GridBean<>(pager.getPage(), pager.getRows(), count, list);
        return new BocloudResult<>(true, gridBean, "查询成功");
    }

    public void removeSchedule(SnapshotModel snapshotParamModel) {
        ScheduledFuture scheduledFuture = SNAPSHOT_FUTURES.remove(snapshotParamModel.getSnapshotUuid());
        scheduledFuture.cancel(true);
        logger.info("快照[{}]更新大小任务已经从定时同步任务中移除", snapshotParamModel.getName());
    }

    /**
     * 同步快照独立占用空间的大小
     */
    public BocloudResult syncSnapshotUniqueSize(SnapshotModel snapshotParamModel, CloudVendor vendor, RequestContext context){

        logger.info(snapshotParamModel.getName()+"快照同步size");
        Snapshot snapshot = snapshotRepository.getBySnapUuid(snapshotParamModel.getSnapshotUuid());

        OperateResult operateResult = new OperateResult(true, "", vendor.getType().toLowerCase() + ".volume",
                MapTools.simpleMap("vendorId", vendor.getId()), OperateResult.OperateCategory.ResourceEvent, context);
        snapshotParamModel.setSnapshotType("VOLUME");
        snapshotParamModel.setSnapshotUuid(snapshotParamModel.getSnapshotUuid());
         BocloudResult bocloudResult = snapshotDriver.detail(vendor.getUuid(), null, snapshotParamModel);
        if (bocloudResult.isFailed()) {
            operateResult.setSuccess(false);
            operateResult.setMessage("更新快照大小失败：" + bocloudResult.getMessage());
            resourceEventPublisher.send(operateResult);
            return new BocloudResult(false, snapshot.getName() +"快照大小更新失败" +bocloudResult.getMessage());
        }
        SnapshotModel snapshotResultModel = (SnapshotModel) bocloudResult.getData();
        // 快照数据更新数据
        snapshot.setSize(snapshotResultModel.getSize());
        snapshotRepository.update(snapshot);

        if(snapshot.getSize()!=-1 && SNAPSHOT_FUTURES.containsKey(snapshotParamModel.getSnapshotUuid())){
            this.removeSchedule(snapshotParamModel);
            // 发送异步消息
            operateResult.setSuccess(true);
            operateResult.setMessage(snapshot.getName()+"快照大小更新成功");
            resourceEventPublisher.send(operateResult);
            return new BocloudResult(true,"快照大小更新成功");
        }
        return new BocloudResult(true, "快照大小更新中");
    }

    public void addSchedule(SnapshotModel snapshotParamModel, CloudVendor vendor, RequestContext context) {
        Trigger trigger = new CronTrigger("*/5 * * * * ?  ");
        ScheduledFuture future = taskScheduler.schedule(() -> this.syncSnapshotUniqueSize(snapshotParamModel, vendor, context), trigger);
        SNAPSHOT_FUTURES.put(snapshotParamModel.getSnapshotUuid(), future);
        logger.info("快照[{}]更新大小任务定时策略:" + "*/5 * * * * ?  ", snapshotParamModel.getName());
    }
}
