package com.bocloud.ims.service.resource;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.loadbalance.LbDriver;
import com.bocloud.cmp.entity.enums.BocloudStatus.Server;
import com.bocloud.cmp.entity.enums.CloudProvider;
import com.bocloud.cmp.entity.enums.ResourceCategory;
import com.bocloud.cmp.model.FirewallModel;
import com.bocloud.cmp.model.NetworkBean;
import com.bocloud.cmp.model.VolBean;
import com.bocloud.cmp.model.common.ApplicationParam;
import com.bocloud.cmp.model.common.DurationModel;
import com.bocloud.cmp.model.common.DurationModel.Mode;
import com.bocloud.cmp.model.common.ElementModel;
import com.bocloud.cmp.model.common.EmptionModel;
import com.bocloud.cmp.model.common.OrderItem;
import com.bocloud.cmp.model.common.OrderMessage;
import com.bocloud.cmp.model.common.OrderMessage.Operation;
import com.bocloud.cmp.model.common.QuotaBean;
import com.bocloud.cmp.model.common.ServiceOrder;
import com.bocloud.cmp.model.common.SpecModel;
import com.bocloud.cmp.vm.model.AttachNetworkParam;
import com.bocloud.cmp.vm.model.VmGenericParam;
import com.bocloud.common.encrypt.AESEncrptor;
import com.bocloud.common.encrypt.Encryptor;
import com.bocloud.common.enums.PostDataFormat;
import com.bocloud.common.http.HttpClient;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.RequestContext;
import com.bocloud.common.model.Result;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.IDFactory;
import com.bocloud.common.utils.JSONTools;
import com.bocloud.common.utils.ListTool;
import com.bocloud.common.utils.ResultTools;
import com.bocloud.ims.entity.common.Tenant;
import com.bocloud.ims.entity.middleware.K8sCluster;
import com.bocloud.ims.entity.middleware.K8sNode;
import com.bocloud.ims.entity.resource.CloudServer;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.Firewall;
import com.bocloud.ims.entity.resource.FirewallPolicy;
import com.bocloud.ims.entity.resource.FirewallRule;
import com.bocloud.ims.entity.resource.Ip;
import com.bocloud.ims.entity.resource.LBAddBean;
import com.bocloud.ims.entity.resource.LbListener;
import com.bocloud.ims.entity.resource.LbMember;
import com.bocloud.ims.entity.resource.LbPool;
import com.bocloud.ims.entity.resource.LoadBalancer;
import com.bocloud.ims.entity.resource.ObjectRelation;
import com.bocloud.ims.entity.resource.ResourceQuota;
import com.bocloud.ims.entity.resource.ResourceQuota.Action;
import com.bocloud.ims.entity.resource.Router;
import com.bocloud.ims.entity.resource.SecurityGroup;
import com.bocloud.ims.entity.resource.SecurityGroupRule;
import com.bocloud.ims.entity.resource.Subnet;
import com.bocloud.ims.entity.resource.Volume;
import com.bocloud.ims.interfaces.resource.CloudServerService;
import com.bocloud.ims.interfaces.resource.FirewallPolicyService;
import com.bocloud.ims.interfaces.resource.FirewallRuleService;
import com.bocloud.ims.interfaces.resource.FirewallService;
import com.bocloud.ims.interfaces.resource.IpService;
import com.bocloud.ims.interfaces.resource.LbListenerService;
import com.bocloud.ims.interfaces.resource.LbMemberService;
import com.bocloud.ims.interfaces.resource.LbPoolService;
import com.bocloud.ims.interfaces.resource.LoadBalancerService;
import com.bocloud.ims.interfaces.resource.NetworkService;
import com.bocloud.ims.interfaces.resource.RosProcessService;
import com.bocloud.ims.interfaces.resource.RouterService;
import com.bocloud.ims.interfaces.resource.SecurityGroupRuleService;
import com.bocloud.ims.interfaces.resource.SecurityGroupService;
import com.bocloud.ims.interfaces.resource.SubnetService;
import com.bocloud.ims.interfaces.resource.VMApplyService;
import com.bocloud.ims.interfaces.resource.VMExtendService;
import com.bocloud.ims.interfaces.resource.VolumeService;
import com.bocloud.ims.repository.resource.CloudVendorRepository;
import com.bocloud.ims.repository.resource.IpRepository;
import com.bocloud.ims.repository.resource.K8sClusterRepository;
import com.bocloud.ims.repository.resource.K8sNodeRepository;
import com.bocloud.ims.repository.resource.ObjectRelationRepository;
import com.bocloud.ims.service.builder.ServerBuilder;
import com.bocloud.ims.service.internal.CosInternalService;
import com.bocloud.ims.service.internal.SmsInternalService;
import com.bocloud.ims.service.internal.SmsSystemConfigService;
import com.bocloud.ims.service.internal.SmsTenantService;
import com.bocloud.ims.service.model.ProcessResult;
import com.bocloud.ims.service.utils.ServerOperationHelper;
import com.bocloud.nms.enums.OrderItemStatus;

/**
 * 编排资源创建任务类
 *
 * @author wangyu
 * @Date 2020-7-31 15:15:29
 */
@Service("rosProcessService")
public class RosProcessServiceImpl implements RosProcessService {

    private static Logger logger = LoggerFactory.getLogger(RosProcessServiceImpl.class);
    @Autowired
    private CloudVendorRepository cloudVendorRepository;
    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    private ServerOperationHelper serverOperationHelper;
    @Autowired
    private SubnetService subnetService;
    @Autowired
    private RouterService routerService;
    @Autowired
    private VolumeService volumeService;
    @Autowired
    private SecurityGroupService securityGroupService;
    @Autowired
    private SecurityGroupRuleService securityGroupRuleService;
    @Autowired
    private NetworkService networkService;
    @Autowired
    private CloudServerService cloudServerService;
    @Autowired
    private VMExtendService vmExtendService;
    @Autowired
    private SmsTenantService smsTenantService;
    @Autowired
    private SmsSystemConfigService configService;
    @Autowired
    private CosInternalService cosInternalService;
    @Autowired
    private IpService ipService;
    @Autowired
    private IpRepository ipRepository;
    @Autowired
    private K8sClusterRepository k8sClusterRepository;
    @Autowired
    private K8sNodeRepository k8sNodeRepository;
    @Autowired
    private ObjectRelationRepository objectRelationRepository;
    @Autowired
    private SmsInternalService smsInternalService;
    @Autowired
    private FirewallService firewallService;
    @Autowired
    private FirewallPolicyService firewallPolicyService;
    @Autowired
    private FirewallRuleService firewallRuleService;
    @Autowired
    private LbListenerService lbListenerService;
    @Autowired
    private LoadBalancerService loadBalancerService;
    @Autowired
    private LbMemberService lbMemberService;
    @Autowired
    private LbPoolService lbPoolService;
    @Autowired
    private LbDriver lbDriver;
    @Autowired
    private VMApplyService vmApplyService;
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;

    @Override
    public void createServer(String params, RequestContext context, String queue) {
        JSONObject object = JSONTools.isJSONObj(params);
        if (null == object) {
            send(queue, ResultTools.formatErrResult());
            return;
        }
        JSONObject fronts = JSONObject.parseObject(object.getString("fronts"));
        JSONObject extension = fronts.getJSONObject("extension");
        if (null != extension) {
            fronts.put("osTenantName", extension.getString("osTenantName"));
        }
        if ("create".equals(object.getString("origin"))) {
            JSONObject configs = fronts.getJSONObject("configs");
            if (!StringUtils.isEmpty(configs.getString("software")) || null == context.getTenant()
                || 0 == context.getTenant()) {
                BocloudResult result = vmApplyService.createServer(fronts, context, queue);
                if (result.isFailed()) {
                    send(queue, result);
                }
            } else {
                configs.put("networks", fronts.get("networks"));
                configs.put("groups", fronts.get("groups"));
                fronts.put("configs", configs);
                ApplicationParam param = JSONObject.parseObject(fronts.toJSONString(), ApplicationParam.class);
                if (null == param.getEmption()) {
                    EmptionModel model = new EmptionModel();
                    model.setDuration(new DurationModel(Mode.Hour, 1));
                    model.setCount(1);
                    param.setEmption(model);
                }
                param.setContext(context);
                param.setCallback(queue);
                amqpTemplate.convertAndSend("ros.application.queue", JSONObject.toJSON(param));
            }
        } else {
            BocloudResult result = cloudServerService.basic(fronts.getLong("id"));
            if (result.isFailed()) {
                send(queue, result);
                return;
            }
            if (null == result.getData()) {
                result.setMessage("查询结果为空!");
                result.setSuccess(false);
                send(queue, result);
                return;
            }

            BocloudResult bocloudResult = result;
            List<NetworkBean> networks = JSONArray.parseArray(fronts.getString("networks"), NetworkBean.class);
            if (!ListTool.isEmpty(networks)) {
                bocloudResult = vmExtendService
                    .attachNetwork(JSONObject.parseObject(fronts.toJSONString(), AttachNetworkParam.class), context);
                if (bocloudResult.isFailed()) {
                    send(queue, bocloudResult);
                    return;
                }
            }

            List<Long> groupIds = JSONArray.parseArray(fronts.getString("groupIds"), Long.class);
            if (!ListTool.isEmpty(groupIds)) {
                int count = 0;
                for (Long groupId : groupIds) {
                    bocloudResult = vmExtendService.joinSGroup(fronts.getLong("id"), groupId, context);
                    if (bocloudResult.isSuccess()) {
                        count++;
                    }
                }
                if (count == 0) {
                    bocloudResult = new BocloudResult<>(false, "虚拟机加入安全组失败！");
                } else {
                    bocloudResult =
                        new BocloudResult<>(true, "虚拟机加入安全组成功【" + count + "】个,失败【" + (groupIds.size() - count) + "】个");
                }
            }
            if (bocloudResult.isSuccess()) {
                CloudServer server = (CloudServer)result.getData();
                // 数据库是DES加密，传给cop之前做解密，然后用AES加密传输，底层worker使用AES解密
                logger.debug("password raw: {}, password encrypt: {}", server.receivePswd(), server.getPassword());
                String pswd = server.receivePswd();
                if (!StringUtils.isEmpty(pswd)) {
                    Encryptor encryptor = new AESEncrptor();
                    server.setPassword(encryptor.encrypt(pswd, null));
                }
                result.setData(server);
                send(queue, result);
            } else {
                send(queue, bocloudResult);
            }
        }
    }

    @Override
    public void createVolume(String params, RequestContext context, String queue) {
        JSONObject object = JSONTools.isJSONObj(params);
        if (null == object) {
            send(queue, ResultTools.formatErrResult());
            return;
        }
        JSONObject fronts = JSONObject.parseObject(object.getString("fronts"));
        JSONObject extension = fronts.getJSONObject("extension");
        if (null != extension) {
            fronts.put("osTenantName", extension.getString("osTenantName"));
        }
        if ("create".equals(object.getString("origin"))) {
            if (null == context.getCatalog() || null == context.getTenant() || 0 == context.getTenant()) {
                BocloudResult result = volumeService.createOsVolume(fronts, context);
                send(queue, result);
            } else {
                ApplicationParam param = JSONObject.parseObject(object.getString("fronts"), ApplicationParam.class);
                if (null == param.getEmption()) {
                    EmptionModel model = new EmptionModel();
                    model.setDuration(new DurationModel(Mode.Hour, 1));
                    model.setCount(1);
                    param.setEmption(model);
                }
                param.setContext(context);
                param.setCallback(queue);
                amqpTemplate.convertAndSend("ros.application.queue", JSONObject.toJSON(param));
            }
        } else {
            BocloudResult bocloudResult = volumeService.detail(fronts.getLong("id"));
            if (bocloudResult.isFailed()) {
                send(queue, bocloudResult);
                return;
            }
            Volume volume = JSONObject.parseObject(JSONObject.toJSONString(bocloudResult.getData()), Volume.class);
            Long serverId = fronts.getLong("serverId");
            if (null != serverId) {
                VolBean volBean = new VolBean();
                volBean.setId(volume.getId());
                volBean.setServerId(serverId);
                BocloudResult attachResult = volumeService.attach(volBean, context);
                attachResult.setData(volume);
                send(queue, attachResult);
            } else {
                if (null == bocloudResult.getData()) {
                    bocloudResult.setMessage("查询结果为空!");
                    bocloudResult.setSuccess(false);
                }
                send(queue, bocloudResult);
            }
        }
    }

    @Override
    public void createRouter(String params, RequestContext context, String queue) {
        JSONObject object = JSONTools.isJSONObj(params);
        if (null == object) {
            send(queue, ResultTools.formatErrResult());
            return;
        }
        JSONObject fronts = JSONObject.parseObject(object.getString("fronts"));
        JSONObject extension = fronts.getJSONObject("extension");
        if (null != extension) {
            fronts.put("osTenantName", extension.getString("osTenantName"));
        }
        if ("create".equals(object.getString("origin"))) {
            // 位置
            JSONObject location = fronts.getJSONObject("location");
            fronts.put("name", fronts.getString("name") + System.currentTimeMillis());
            Router router = JSONObject.parseObject(fronts.toJSONString(), Router.class);
            router.setVendorId(location.getLong("vendorId"));
            BocloudResult result = routerService.create(router, context);
            send(queue, result);
        } else {
            BocloudResult bocloudResult = routerService.detail(fronts.getLong("id"));
            if (bocloudResult.isFailed()) {
                send(queue, bocloudResult);
                return;
            }
            if (null == bocloudResult.getData()) {
                bocloudResult.setMessage("查询结果为空!");
                bocloudResult.setSuccess(false);
            }
            send(queue, bocloudResult);
        }
    }

    @Override
    public void createSecGroup(String params, RequestContext context, String queue) {
        JSONObject object = JSONTools.isJSONObj(params);
        if (null == object) {
            send(queue, ResultTools.formatErrResult());
            return;
        }
        JSONObject fronts = JSONObject.parseObject(object.getString("fronts"));
        JSONObject extension = fronts.getJSONObject("extension");
        if (null != extension) {
            fronts.put("osTenantName", extension.getString("osTenantName"));
        }
        if ("create".equals(object.getString("origin"))) {
            fronts.put("name", fronts.getString("name") + System.currentTimeMillis());
            SecurityGroup group = JSONObject.parseObject(fronts.toJSONString(), SecurityGroup.class);
            if (null == group) {
                send(queue, new BocloudResult<>(false, "创建安全组的参数有误!"));
                return;
            }
            // 位置
            JSONObject location = fronts.getJSONObject("location");
            group.setVendorId(location.getLong("vendorId"));
            // 2018年12月21日14:34:26
            BocloudResult result = securityGroupService.create(group, context);
            send(queue, result);
        } else {
            BocloudResult bocloudResult = securityGroupService.detail(fronts.getLong("id"));
            if (bocloudResult.isFailed()) {
                send(queue, bocloudResult);
                return;
            }
            if (null == bocloudResult.getData()) {
                bocloudResult.setMessage("查询结果为空!");
                bocloudResult.setSuccess(false);
            }
            send(queue, bocloudResult);
        }
    }

    @Override
    public void createFirewall(String params, RequestContext context, String queue) {
        JSONObject object = JSONTools.isJSONObj(params);
        if (null == object) {
            send(queue, ResultTools.formatErrResult());
            return;
        }
        JSONObject fronts = JSONObject.parseObject(object.getString("fronts"));
        JSONObject extension = fronts.getJSONObject("extension");
        if (null != extension) {
            fronts.put("osTenantName", extension.getString("osTenantName"));
        }
        if ("create".equals(object.getString("origin"))) {
            fronts.put("name", fronts.getString("name") + System.currentTimeMillis());
            Firewall firewall = JSONObject.parseObject(fronts.toJSONString(), Firewall.class);
            if (null == firewall) {
                send(queue, new BocloudResult<>(false, "创建防火墙的参数有误!"));
                return;
            }
            // 位置
            JSONObject location = fronts.getJSONObject("location");
            firewall.setVendorId(location.getLong("vendorId"));
            BocloudResult result = firewallService.create(firewall, context, queue);
            if (result.isFailed()) {
                send(queue, result);
            }
        } else {
            BocloudResult bocloudResult = firewallService.detail(fronts.getLong("id"));
            if (bocloudResult.isFailed()) {
                send(queue, bocloudResult);
                return;
            }
            Firewall firewall =
                JSONObject.parseObject(JSONObject.toJSONString(bocloudResult.getData()), Firewall.class);
            Long policyId = fronts.getLong("policyId");
            BocloudResult result = null;
            if (null != policyId) {
                firewall.setPolicyId(policyId);
                result = firewallService.modify(firewall, context.getTarget());
                if (result.isFailed()) {
                    send(queue, result);
                    return;
                }
            }
            List<Long> routerIds = JSONArray.parseArray(fronts.getString("routerIds"), Long.class);
            if (!ListTool.isEmpty(routerIds)) {
                firewall.setRouterIds(routerIds);
                result = firewallService.relevanceRouter(firewall.getId(),
                    JSONObject.parseObject(JSONObject.toJSONString(firewall), FirewallModel.class), context);
                if (result.isFailed()) {
                    send(queue, result);
                    return;
                }
            }
            if (null != result && result.isFailed()) {
                send(queue, new BocloudResult<>(false, "处理防火墙相关依赖时出错！"));
                return;
            }
            result = new BocloudResult<>(true, firewall, "防火墙相关依赖处理完成");
            send(queue, result);
        }
    }

    @Override
    public void createSubnet(String params, RequestContext context, String queue) {
        JSONObject object = JSONTools.isJSONObj(params);
        if (null == object) {
            send(queue, ResultTools.formatErrResult());
            return;
        }
        JSONObject fronts = JSONObject.parseObject(object.getString("fronts"));
        JSONObject extension = fronts.getJSONObject("extension");
        if (null != extension) {
            fronts.put("osTenantName", extension.getString("osTenantName"));
        }
        if ("create".equals(object.getString("origin"))) {
            // 位置
            BocloudResult result =
                subnetService.create(JSONObject.parseObject(fronts.toJSONString(), Subnet.class), context);
            if (result.isSuccess()) {
                Subnet subnet = JSONObject.parseObject(JSONObject.toJSONString(result.getData()), Subnet.class);
                // 连接路由
                List<Long> routerIds = JSONArray.parseArray(fronts.getString("routerIds"), Long.class);
                if (!ListTool.isEmpty(routerIds)) {
                    for (Long routerId : routerIds) {
                        routerService.attach(routerId, subnet.getId(), null, null, context);
                    }
                }
            }
            send(queue, result);
        } else {
            BocloudResult bocloudResult = subnetService.detail(fronts.getLong("id"));
            if (bocloudResult.isFailed()) {
                send(queue, bocloudResult);
                return;
            }
            Subnet subnet = JSONObject.parseObject(JSONObject.toJSONString(bocloudResult.getData()), Subnet.class);
            List<Long> routerIds = JSONArray.parseArray(fronts.getString("routerIds"), Long.class);
            if (!ListTool.isEmpty(routerIds)) {
                int count = 0;
                for (Long routerId : routerIds) {
                    BocloudResult result = routerService.attach(routerId, subnet.getId(), null, null, context);
                    if (result.isSuccess()) {
                        count++;
                    }
                }
                if (count == 0) {
                    bocloudResult = new BocloudResult<>(false, "子网连接路由失败！");
                } else {
                    bocloudResult =
                        new BocloudResult<>(true, "子网连接路由成功【" + count + "】个,失败【" + (routerIds.size() - count) + "】个");
                }
                bocloudResult.setData(subnet);
                send(queue, bocloudResult);
            } else {
                if (null == bocloudResult.getData()) {
                    bocloudResult.setMessage("查询结果为空!");
                    bocloudResult.setSuccess(false);
                }
                send(queue, bocloudResult);
            }
        }
    }

    @Override
    public void createNetwork(String params, RequestContext context, String queue) {
        JSONObject object = JSONTools.isJSONObj(params);
        if (null == object) {
            send(queue, new BocloudResult<>(false, "创建网络的参数有误"));
            return;
        }
        JSONObject fronts = JSONObject.parseObject(object.getString("fronts"));
        JSONObject extension = fronts.getJSONObject("extension");
        if (null != extension) {
            fronts.put("osTenantName", extension.getString("osTenantName"));
        }
        if ("create".equals(object.getString("origin"))) {
            if (null == context.getCatalog() || null == context.getTenant() || 0 == context.getTenant()) {
                BocloudResult result = networkService.createOsNetwork(fronts, context);
                send(queue, result);
            } else {
                ApplicationParam param = JSONObject.parseObject(object.getString("fronts"), ApplicationParam.class);
                if (null == param.getEmption()) {
                    EmptionModel model = new EmptionModel();
                    model.setDuration(new DurationModel(Mode.Hour, 1));
                    model.setCount(1);
                    param.setEmption(model);
                }
                param.setContext(context);
                param.setCallback(queue);
                amqpTemplate.convertAndSend("ros.application.queue", JSONObject.toJSON(param));
            }
        } else {
            BocloudResult result = networkService.detail(fronts.getLong("id"));
            if (result.isFailed()) {
                send(queue, result);
                return;
            }
            if (null == result.getData()) {
                result.setMessage("查询结果为空!");
                result.setSuccess(false);
            }
            send(queue, result);
        }
    }

    @Override
    public void createFirewallPolicy(String params, RequestContext context, String queue) {
        JSONObject object = JSONTools.isJSONObj(params);
        if (null == object) {
            send(queue, new BocloudResult<>(false, "创建防火墙策略的参数有误"));
            return;
        }
        JSONObject fronts = JSONObject.parseObject(object.getString("fronts"));
        JSONObject extension = fronts.getJSONObject("extension");
        if (null != extension) {
            fronts.put("osTenantName", extension.getString("osTenantName"));
        }
        if ("create".equals(object.getString("origin"))) {
            fronts.put("name", fronts.getString("name") + System.currentTimeMillis());
            FirewallPolicy policy = JSONObject.parseObject(fronts.toJSONString(), FirewallPolicy.class);
            if (null == policy) {
                send(queue, new BocloudResult<>(false, "创建防火墙策略的参数有误"));
                return;
            }
            // 位置
            JSONObject location = fronts.getJSONObject("location");
            policy.setVendorId(location.getLong("vendorId"));
            send(queue, firewallPolicyService.create(policy, context));
        } else {
            BocloudResult result = firewallPolicyService.detail(fronts.getLong("id"));
            if (result.isFailed()) {
                send(queue, result);
                return;
            }
            List<Long> ruleIds = JSONArray.parseArray(fronts.getString("ruleIds"), Long.class);
            if (!ListTool.isEmpty(ruleIds)) {
                int count = 0;
                for (Long ruleId : ruleIds) {
                    FirewallPolicy firewallPolicy = new FirewallPolicy();
                    firewallPolicy.setRuleId(ruleId);
                    firewallPolicy.setId(fronts.getLong("id"));
                    BocloudResult bocloudResult = firewallPolicyService.insertRule(firewallPolicy, context.getTarget());
                    if (bocloudResult.isSuccess()) {
                        count++;
                    }
                }
                if (count == 0) {
                    result = new BocloudResult<>(false, "防火墙策略插入规则失败！");
                } else {
                    result =
                        new BocloudResult<>(true, "防火墙策略插入规则成功【" + count + "】个,失败【" + (ruleIds.size() - count) + "】个");
                }
                result.setData(result.getData());
                send(queue, result);
            } else {
                if (null == result.getData()) {
                    result.setMessage("查询结果为空!");
                    result.setSuccess(false);
                }
                send(queue, result);
            }
        }
    }

    @Override
    public void createFirewallRule(String params, RequestContext context, String queue) {
        JSONObject object = JSONTools.isJSONObj(params);
        if (null == object) {
            send(queue, new BocloudResult<>(false, "创建防火墙规则的参数有误"));
            return;
        }
        JSONObject fronts = JSONObject.parseObject(object.getString("fronts"));
        JSONObject extension = fronts.getJSONObject("extension");
        if (null != extension) {
            fronts.put("osTenantName", extension.getString("osTenantName"));
        }
        if ("create".equals(object.getString("origin"))) {
            fronts.put("name", fronts.getString("name") + System.currentTimeMillis());
            FirewallRule rule = JSONObject.parseObject(fronts.toJSONString(), FirewallRule.class);
            if (null == rule) {
                send(queue, new BocloudResult<>(false, "创建防火墙规则的参数有误"));
                return;
            }
            // 位置
            JSONObject location = fronts.getJSONObject("location");
            rule.setVendorId(location.getLong("vendorId"));
            send(queue, firewallRuleService.create(rule, context));
        } else {
            BocloudResult result = firewallRuleService.detail(fronts.getLong("id"));
            if (result.isFailed()) {
                send(queue, result);
                return;
            }
            if (null == result.getData()) {
                result.setMessage("查询结果为空!");
                result.setSuccess(false);
            }
            send(queue, result);
        }
    }

    @Override
    public void createLoadBalancer(String params, RequestContext context, String queue) {
        JSONObject object = JSONTools.isJSONObj(params);
        if (null == object) {
            send(queue, new BocloudResult<>(false, "创建负载均衡器的参数有误"));
            return;
        }
        JSONObject fronts = JSONObject.parseObject(object.getString("fronts"));
        JSONObject extension = fronts.getJSONObject("extension");
        if (null != extension) {
            fronts.put("osTenantName", extension.getString("osTenantName"));
        }
        if ("create".equals(object.getString("origin"))) {
            // 位置
            JSONObject location = fronts.getJSONObject("location");
            LoadBalancer balancer = JSONObject.parseObject(fronts.toJSONString(), LoadBalancer.class);
            balancer.setVendorId(location.getLong("vendorId"));
            balancer.setName(balancer.getName() + "_" + System.currentTimeMillis());
            LBAddBean bean = new LBAddBean();
            bean.setBalancer(balancer);
            BocloudResult result = loadBalancerService.create(bean, context, queue);
            if (result.isFailed()) {
                send(queue, result);
            }
        } else {
            BocloudResult result = loadBalancerService.detail(fronts.getLong("id"));
            if (result.isFailed()) {
                send(queue, result);
                return;
            }
            if (null == result.getData()) {
                result.setMessage("查询结果为空!");
                result.setSuccess(false);
            }
            send(queue, result);
        }
    }

    @Override
    public void createListener(String params, RequestContext context, String queue) {
        JSONObject object = JSONTools.isJSONObj(params);
        if (null == object) {
            send(queue, new BocloudResult<>(false, "创建监听器的参数有误"));
            return;
        }
        JSONObject fronts = JSONObject.parseObject(object.getString("fronts"));
        JSONObject extension = fronts.getJSONObject("extension");
        if (null != extension) {
            fronts.put("osTenantName", extension.getString("osTenantName"));
        }
        if ("create".equals(object.getString("origin"))) {
            try {
                LBAddBean bean = JSONObject.parseObject(fronts.toJSONString(), LBAddBean.class);
                if (null == bean) {
                    send(queue, new BocloudResult<>(false, "创建监听器的参数格式有误"));
                    return;
                }
                LbListener listener =
                    JSONObject.parseObject(JSONObject.toJSONString(bean.getListener()), LbListener.class);
                if (null == listener) {
                    send(queue, new BocloudResult<>(false, "创建监听器的参数格式有误"));
                    return;
                }
                listener.setName(listener.getName() + "_" + System.currentTimeMillis());
                // 位置
                JSONObject location = fronts.getJSONObject("location");
                listener.setVendorId(location.getLong("vendorId"));
                Long lbId = listener.getLbId();
                if (null == lbId) {
                    lbId = fronts.getLong("lbId");
                    listener.setLbId(lbId);
                }
                if (null == lbId) {
                    send(queue, new BocloudResult<>(false, "创建监听器的参数格式有误"));
                    return;
                }
                BocloudResult result = loadBalancerService.detail(lbId);
                if (result.isFailed()) {
                    send(queue, new BocloudResult<>(false, "负载均衡器不存在"));
                    return;
                }
                LoadBalancer balancer =
                    JSONObject.parseObject(JSONObject.toJSONString(result.getData()), LoadBalancer.class);
                CloudVendor vendor = cloudVendorRepository.query(balancer.getVendorId());
                if (null == vendor) {
                    send(queue, new BocloudResult<>(false, "所属云平台不存在"));
                    return;
                }
                boolean flag = getActiveLb(balancer.getLbUuid(), vendor.getUuid());
                if (!flag) {
                    send(queue, new BocloudResult<>(false, "负载均衡器状态异常，创建监听器失败"));
                    return;
                }
                BocloudResult bocloudResult = lbListenerService.create(bean, context, queue);
                if (bocloudResult.isFailed()) {
                    send(queue, bocloudResult);
                }
            } catch (Exception e) {
                logger.error("Get error message：", e);
                send(queue, new BocloudResult<>(false, "创建监听器失败"));
                return;
            }
        } else {
            BocloudResult result = lbListenerService.detail(fronts.getLong("id"));
            if (result.isFailed()) {
                send(queue, result);
                return;
            }
            LbListener listener = JSONObject.parseObject(JSONObject.toJSONString(result.getData()), LbListener.class);
            if (null == listener) {
                send(queue, new BocloudResult<>(false, "监听器不存在"));
                return;
            }
            BocloudResult bocloudResult = lbPoolService.listByListenerId(listener.getId());
            if (bocloudResult.isFailed()) {
                send(queue, new BocloudResult<>(false, "成员池不存在"));
                return;
            }
            List<LbPool> lbPools = JSONArray.parseArray(JSONObject.toJSONString(bocloudResult.getData()), LbPool.class);
            if (ListTool.isEmpty(lbPools)) {
                send(queue, new BocloudResult<>(false, "成员池不存在"));
                return;
            }
            listener.setPoolId(lbPools.get(0).getId());
            result.setData(listener);
            if (null == result.getData()) {
                result.setMessage("查询结果为空!");
                result.setSuccess(false);
            }
            send(queue, result);
        }
    }

    /**
     * 获取激活状态下的负载均衡器
     *
     * @param lbId
     * @param vendor
     * @return
     */
    private boolean getActiveLb(String lbId, String vendor) {
        BocloudResult result = lbDriver.detail(lbId, vendor, null);
        boolean flag = true;
        Long startTime = System.currentTimeMillis();
        LoadBalancer loadBalancer = null;
        while (flag) {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                logger.error("Get error message:", e);
                Thread.currentThread().interrupt();
            }
            if (result.isFailed()) {
                flag = false;
                break;
            }
            LoadBalancer balancer =
                JSONObject.parseObject(JSONObject.toJSONString(result.getData()), LoadBalancer.class);
            if (null == balancer) {
                flag = false;
                break;
            }
            if ("RUNNING".equalsIgnoreCase(balancer.getProvisioningStatus())) {
                loadBalancer = balancer;
                flag = false;
                break;
            }
            Long endTime = System.currentTimeMillis();
            if (endTime - startTime > 10 * 60 * 1000) {
                flag = false;
                break;
            }
            result = lbDriver.detail(lbId, vendor, null);
        }
        if (null != loadBalancer) {
            return true;
        }
        return false;
    }

    @Override
    public void createLbMember(String params, RequestContext context, String queue) {
        JSONObject object = JSONObject.parseObject(params);
        if (null == object) {
            send(queue, new BocloudResult<>(false, "添加监听器成员的参数有误"));
            return;
        }
        JSONObject fronts = JSONObject.parseObject(object.getString("fronts"));
        JSONObject extension = fronts.getJSONObject("extension");
        if (null != extension) {
            fronts.put("osTenantName", extension.getString("osTenantName"));
        }
        if ("create".equals(object.getString("origin"))) {
            List<LbMember> members = JSONObject.parseArray(fronts.getString("members"), LbMember.class);
            if (ListTool.isEmpty(members)) {
                send(queue, new BocloudResult<>(true, "无成员添加"));
            }
            // 位置
            JSONObject location = fronts.getJSONObject("location");
            Long poolId = fronts.getLong("poolId");
            Long vendorId = location.getLong("vendorId");
            Long lbId = fronts.getLong("lbId");
            BocloudResult result = loadBalancerService.detail(lbId);
            if (result.isFailed()) {
                send(queue, new BocloudResult<>(false, "负载均衡器不存在"));
                return;
            }
            LoadBalancer balancer =
                JSONObject.parseObject(JSONObject.toJSONString(result.getData()), LoadBalancer.class);
            try {
                CloudVendor vendor = cloudVendorRepository.query(balancer.getVendorId());
                if (null == vendor) {
                    send(queue, new BocloudResult<>(false, "所属云平台不存在"));
                    return;
                }
                boolean flag = getActiveLb(balancer.getLbUuid(), vendor.getUuid());
                if (!flag) {
                    send(queue, new BocloudResult<>(false, "负载均衡器状态异常，创建成员失败"));
                    return;
                }
            } catch (Exception e) {
                logger.error("Get error message：", e);
                send(queue, new BocloudResult<>(false, "创建监听器失败"));
                return;
            }
            BocloudResult bocloudResult = lbMemberService.manage(members, null, context, vendorId, poolId, queue);
            if (bocloudResult.isFailed()) {
                send(queue, bocloudResult);
            }
        } else {
            BocloudResult result = lbMemberService.detail(fronts.getLong("id"));
            if (result.isFailed()) {
                send(queue, result);
                return;
            }
            if (null == result.getData()) {
                result.setMessage("查询结果为空!");
                result.setSuccess(false);
            }
            send(queue, result);
        }
    }

    @Override
    public void createSecGroupRule(String params, RequestContext context, String queue) {
        JSONObject object = JSONTools.isJSONObj(params);
        if (null == object) {
            send(queue, new BocloudResult<>(false, "创建防火墙策略的参数有误"));
            return;
        }
        JSONObject fronts = JSONObject.parseObject(object.getString("fronts"));
        JSONObject extension = fronts.getJSONObject("extension");
        if (null != extension) {
            fronts.put("osTenantName", extension.getString("osTenantName"));
        }
        if ("create".equals(object.getString("origin"))) {
            SecurityGroupRule rule = JSONObject.parseObject(fronts.toJSONString(), SecurityGroupRule.class);
            if (null == rule) {
                send(queue, new BocloudResult<>(false, "创建安全组规则的参数有误"));
                return;
            }
            rule.setCreatorId(context.getTarget());
            rule.setTenantId(context.getTenant());
            rule.setProjectId(context.getProject());
            rule.setGroupId(fronts.getLong("groupId"));
            send(queue, securityGroupRuleService.create(rule));
        } else {
            BocloudResult result = securityGroupRuleService.detail(fronts.getLong("id"));
            if (result.isFailed()) {
                send(queue, result);
                return;
            }
            if (null == result.getData()) {
                result.setMessage("查询结果为空!");
                result.setSuccess(false);
            }
            send(queue, result);
        }
    }

    private void send(String queue, BocloudResult result) {
        this.amqpTemplate.convertAndSend(queue, result);
    }

    /**
     * 回收IP
     *
     * @param ips
     */
    private void recycleIp(List<Ip> ips) {
        try {
            if (!ListTool.isEmpty(ips)) {
                for (Ip ip : ips) {
                    ipRepository.delete(ip.getPoolId(), ip.getIp());
                }
            }
            logger.info("End to recovery failed IP address");
        } catch (Exception e) {
            logger.error("Get error Message:", e);
        }
    }

    /**
     * 回滚配额
     *
     * @param elementModels
     * @param projectId
     * @param count
     */
    private void callbackQuotas(List<ElementModel> elementModels, Long projectId, Integer count) {
        Map<String, Integer> quotaMap = new HashMap<>();
        for (ElementModel element : elementModels) {
            quotaMap.put(element.getServiceCode(), count);
            List<SpecModel> specs = element.getSpecs();
            if (ListTool.isEmpty(specs)) {
                continue;
            }
            for (SpecModel spec : specs) {
                if (null != spec.getCpu()) {
                    quotaMap.put("meta.cpu", count * spec.getCpu() * element.getCount());
                } else if (null != spec.getMemory()) {
                    quotaMap.put("meta.mem", count * spec.getMemory().intValue() * element.getCount());
                } else if (null != spec.getDisk()) {
                    String key = "meta.disk";
                    if (quotaMap.containsKey(key)) {
                        quotaMap.put(key, quotaMap.get(key) + count * spec.getDisk() * element.getCount());
                    } else {
                        quotaMap.put(key, count * spec.getDisk() * element.getCount());
                    }
                }
            }
        }
        List<ResourceQuota> beans = new ArrayList<>();
        for (String key : quotaMap.keySet()) {
            beans.add(new ResourceQuota(key, Long.valueOf(quotaMap.get(key))));
        }
        cosInternalService.updateQuotas(beans, Action.Callback, projectId);
    }

    @Override
    public BocloudResult createK8sVm(JSONObject params) {
        String elements = params.getString("elements");
        if (StringUtils.isEmpty(elements)) {
            return ResultTools.formatErrResult();
        }
        List<ElementModel> elementModels = JSONArray.parseArray(elements, ElementModel.class);
        RequestContext context = JSONObject.parseObject(params.getString(Common.CONTEXT), RequestContext.class);
        try {
            JSONObject configs = JSONObject.parseObject(params.getString("configs"));
            if (null == configs) {
                this.callbackQuotas(elementModels, context.getProject(), 1);
                this.callBoc(params.getString("callback"), new JSONObject(),
                    "/boclouddeployerapi/cmpCluster/v2.4/createCluster", "failed", "configs参数不正确", context);
                return ResultTools.formatErrResult();
            }
            logger.info("接收到k8s申请创建虚拟机请求：" + params.toJSONString());
            Long vpcId = configs.getLong("vpcId");
            Long subnetId = configs.getLong("subnetId");
            String diskCategory = configs.getString("diskCategory");
            JSONObject location = JSONObject.parseObject(params.getString("location"));
            if (null == location) {
                this.callbackQuotas(elementModels, context.getProject(), 1);
                this.callBoc(params.getString("callback"), new JSONObject(),
                    "/boclouddeployerapi/cmpCluster/v2.4/createCluster", "failed", "location参数不正确", context);
                return ResultTools.formatErrResult();
            }
            String templateName = configs.getString("templateName");
            CloudVendor vendor = cloudVendorRepository.getByRegion(location.getString("region"),
                location.getString("az"), CloudProvider.VMWARE.name());
            if (null == vendor) {
                this.callbackQuotas(elementModels, context.getProject(), 1);
                this.callBoc(params.getString("callback"), new JSONObject(),
                    "/boclouddeployerapi/cmpCluster/v2.4/createCluster", "failed", "当前可用域下无云平台", context);
                return new BocloudResult<>(false, "当前可用域下无云平台");
            }
            BocloudResult<Tenant> tenantResult = smsTenantService.detail(context.getTenant());
            if (tenantResult.isFailed() || null == tenantResult.getData()) {
                this.callbackQuotas(elementModels, context.getProject(), 1);
                this.callBoc(params.getString("callback"), new JSONObject(),
                    "/boclouddeployerapi/cmpCluster/v2.4/createCluster", "failed", "申请人所在租户不存在", context);
                return new BocloudResult<>(false, "申请人所在租户不存在");
            }
            Tenant tenant = tenantResult.getData();
            Integer masterVipCount = configs.getInteger("masterVipCount");
            List<Ip> masterVips = new ArrayList<>();
            if (null != masterVipCount) {
                if (null == vpcId) {
                    BocloudResult<List<Ip>> result = ipService.achieveIps(Long.valueOf(masterVipCount), "V4");
                    if (result.isFailed()) {
                        this.callbackQuotas(elementModels, context.getProject(), 1);
                        this.callBoc(params.getString("callback"), new JSONObject(),
                            "/boclouddeployerapi/cmpCluster/v2.4/createCluster", "failed", "从管理平台IP池分配IP地址失败", context);
                        return new BocloudResult<>(false, result.getMessage());
                    }
                    masterVips = result.getData();
                } else {
                    masterVips = serverOperationHelper.getNsxIp(null, null, vendor, masterVipCount);
                }
                if (ListTool.isEmpty(masterVips)) {
                    this.callbackQuotas(elementModels, context.getProject(), 1);
                    this.callBoc(params.getString("callback"), new JSONObject(),
                        "/boclouddeployerapi/cmpCluster/v2.4/createCluster", "failed", "master vip分配失败，剩余IP不足",
                        context);
                    return new BocloudResult<>(false, "master vip分配失败，剩余IP不足");
                }
            }
            Integer ingressVipCount = configs.getInteger("ingressVipCount");
            List<Ip> ingressVips = new ArrayList<>();
            if (null != ingressVipCount) {
                if (null == vpcId) {
                    BocloudResult<List<Ip>> result = ipService.achieveIps(Long.valueOf(ingressVipCount), "V4");
                    if (result.isFailed()) {
                        this.callbackQuotas(elementModels, context.getProject(), 1);
                        this.callBoc(params.getString("callback"), new JSONObject(),
                            "/boclouddeployerapi/cmpCluster/v2.4/createCluster", "failed", "从管理平台IP池分配IP地址失败", context);
                        return new BocloudResult<>(false, result.getMessage());
                    }
                    ingressVips = result.getData();
                } else {
                    ingressVips = serverOperationHelper.getNsxIp(vpcId, subnetId, vendor, ingressVipCount);
                }
                if (ListTool.isEmpty(ingressVips)) {
                    this.callbackQuotas(elementModels, context.getProject(), 1);
                    this.recycleIp(masterVips);
                    this.callBoc(params.getString("callback"), new JSONObject(),
                        "/boclouddeployerapi/cmpCluster/v2.4/createCluster", "failed", "ingress vip分配失败，剩余IP不足",
                        context);
                    return new BocloudResult<>(false, "ingress vip分配失败，剩余IP不足");
                }
            }
            List<String> masterVipList = new ArrayList<>();
            masterVips.forEach(m -> masterVipList.add(m.getIp()));
            List<String> ingressVipList = new ArrayList<>();
            ingressVips.forEach(i -> ingressVipList.add(i.getIp()));
            final List<Ip> finalMasterVips = masterVips;
            final List<Ip> finalIngressVips = ingressVips;
            taskExecutor.execute(() -> {
                JSONObject master = JSONObject.parseObject(configs.getString("master"));
                master.put("vendorId", vendor.getId());
                master.put("vpcId", vpcId);
                master.put("subnetId", subnetId);
                master.put("templateName", templateName);
                master.put("diskCategory", diskCategory);
                Integer masterCount = null == master.getInteger("count") ? 0 : master.getInteger("count");
                JSONObject nodes = JSONObject.parseObject(configs.getString("nodes"));
                nodes.put("vendorId", vendor.getId());
                nodes.put("vpcId", vpcId);
                nodes.put("subnetId", subnetId);
                nodes.put("templateName", templateName);
                nodes.put("diskCategory", diskCategory);
                Integer nodesCount = null == nodes.getInteger("count") ? 0 : nodes.getInteger("count");
                JSONObject nfs = new JSONObject();
                Integer nfsCount = 0;
                if (configs.containsKey("nfs")) {
                    nfs = JSONObject.parseObject(configs.getString("nfs"));
                    nfs.put("vendorId", vendor.getId());
                    nfs.put("vpcId", vpcId);
                    nfs.put("subnetId", subnetId);
                    nfs.put("templateName", templateName);
                    nfs.put("diskCategory", diskCategory);
                    nfsCount = null == nfs.getInteger("count") ? 0 : nfs.getInteger("count");
                }
                List<JSONObject> processList = new ArrayList<>();
                String masterHostNames = configs.getString("masterHostNames");
                logger.info("master hostname：{}", masterHostNames);
                List<String> masterHostNameList = new ArrayList<>();
                if (!StringUtils.isEmpty(masterHostNames)) {
                    masterHostNameList = JSONArray.parseArray(masterHostNames, String.class);
                }
                for (int i = 0; i < masterCount; i++) {
                    JSONObject newMaster = JSONObject.parseObject(master.toJSONString());
                    newMaster.put("name", tenant.getAccount() + "_k8s_master_" + IDFactory.instance().mac());
                    newMaster.put("count", 1);
                    newMaster.put("vmHostName", masterHostNameList.get(i));
                    processList.add(newMaster);
                }
                String nodeHostNames = configs.getString("nodeHostNames");
                logger.info("node hostname：{}", nodeHostNames);
                List<String> nodeHostNameList = new ArrayList<>();
                if (!StringUtils.isEmpty(nodeHostNames)) {
                    nodeHostNameList = JSONArray.parseArray(nodeHostNames, String.class);
                }
                for (int i = 0; i < nodesCount; i++) {
                    JSONObject newNode = JSONObject.parseObject(nodes.toJSONString());
                    newNode.put("name", tenant.getAccount() + "_k8s_node_" + IDFactory.instance().mac());
                    newNode.put("count", 1);
                    newNode.put("vmHostName", nodeHostNameList.get(i));
                    processList.add(newNode);
                }
                if (nfsCount != 0) {
                    String nfsHostNames = configs.getString("nfsHostNames");
                    logger.info("nfs hostname：{}", nfsHostNames);
                    List<String> nfsHostNameList = new ArrayList<>();
                    if (!StringUtils.isEmpty(nfsHostNames)) {
                        nfsHostNameList = JSONArray.parseArray(nfsHostNames, String.class);
                    }
                    for (int i = 0; i < nfsCount; i++) {
                        JSONObject newNfs = JSONObject.parseObject(nfs.toJSONString());
                        newNfs.put("name", tenant.getAccount() + "_k8s_nfs_" + IDFactory.instance().mac());
                        newNfs.put("count", 1);
                        newNfs.put("vmHostName", nfsHostNameList.get(i));
                        processList.add(newNfs);
                    }
                }
                List<Future<BocloudResult<CloudServer>>> futures = new ArrayList<>();
                for (JSONObject object : processList) {
                    BocloudResult<ServerBuilder> builderResult =
                        serverOperationHelper.getProcess(CloudProvider.VMWARE, vendor, context);
                    if (builderResult.isFailed()) {
                        continue;
                    }
                    final ServerBuilder process = builderResult.getData();
                    BocloudResult<ProcessResult> processResult = serverOperationHelper.prepare(
                        JSONObject.parseObject(object.toJSONString(), VmGenericParam.class), context, vendor, process);
                    if (processResult.isFailed()) {
                        continue;
                    }
                    final CloudServer server = processResult.getData().getCloudServer();
                    futures.add(taskExecutor.submit(() -> {
                        return serverOperationHelper.builder(CloudProvider.VMWARE.name(), vendor.getId(), server,
                            context, process, "k8s.callback");
                    }));
                }
                List<JSONObject> masterVms = new ArrayList<>();
                List<JSONObject> nodeVms = new ArrayList<>();
                List<JSONObject> nfsVms = new ArrayList<>();
                List<String> messages = new ArrayList<>();
                for (int i = 0; i < futures.size(); i++) {
                    try {
                        BocloudResult<CloudServer> result = futures.get(i).get(1, TimeUnit.HOURS);
                        if (result.isSuccess()) {
                            CloudServer server = result.getData();
                            if (null == server) {
                                continue;
                            }
                            JSONObject vmObj = new JSONObject();
                            vmObj.put("name", server.getName());
                            vmObj.put("account",
                                StringUtils.isEmpty(server.getAccount()) ? "root" : server.getAccount());
                            vmObj.put("port", 22);
                            vmObj.put("password", server.receivePswd());
                            String privateIps = server.getPrivateIps();
                            String businessIp = null;
                            String managerIp = server.getManagerIp();
                            if (!StringUtils.isEmpty(privateIps)) {
                                List<JSONObject> privateIpList = JSONArray.parseArray(privateIps, JSONObject.class);
                                for (JSONObject privateIp : privateIpList) {
                                    if (!managerIp.equalsIgnoreCase(privateIp.getString("address"))) {
                                        businessIp = privateIp.getString("address");
                                        break;
                                    }
                                }
                            }
                            vmObj.put("businessIp", businessIp);
                            vmObj.put("managerIp", managerIp);
                            vmObj.put("instanceId", server.getInstanceId());
                            vmObj.put("vendorId", server.getVendorId());
                            if (server.getName().contains("master")) {
                                masterVms.add(vmObj);
                            } else if (server.getName().contains("node")) {
                                nodeVms.add(vmObj);
                            } else if (server.getName().contains("nfs")) {
                                nfsVms.add(vmObj);
                            }
                        } else {
                            messages.add(result.getMessage());
                        }
                    } catch (Exception e) {
                        logger.error("Get error message：", e);
                    }
                }
                JSONObject result = new JSONObject();
                result.put("masterList", masterVms);
                result.put("nodeList", nodeVms);
                result.put("nfsList", nfsVms);
                result.put("masterVip", masterVipList);
                result.put("ingressVip", ingressVipList);
                logger.info("虚拟机创建结果：" + result.toJSONString());
                if (masterVms.size() + nodeVms.size() + nfsVms.size() == processList.size()) {
                    this.callBoc(params.getString("callback"), result,
                        "/boclouddeployerapi/cmpCluster/v2.4/createCluster", "success", "虚拟机创建成功", context);
                    try {
                        this.saveK8s(params, masterVms, nodeVms, nfsVms, context);
                    } catch (Exception e) {
                        logger.error("Get error message：{}", e.getMessage());
                    }
                } else {
                    logger.error("k8s虚拟机创建失败，开始处理回滚逻辑");
                    List<String> instanceIds = new ArrayList<>();
                    masterVms.forEach(m -> instanceIds.add(m.getString("instanceId")));
                    nodeVms.forEach(m -> instanceIds.add(m.getString("instanceId")));
                    nfsVms.forEach(m -> instanceIds.add(m.getString("instanceId")));
                    vmExtendService.removeByInstanceIds(JSONObject.toJSONString(instanceIds), context);
                    try {
                        for (Ip masterVip : finalMasterVips) {
                            ipRepository.delete(masterVip.getId());
                        }
                        for (Ip ingressVip : finalIngressVips) {
                            ipRepository.delete(ingressVip.getId());
                        }
                    } catch (Exception e) {
                        logger.error("Get error message：{}", e.getMessage());
                    }
                    this.callBoc(params.getString("callback"), new JSONObject(),
                        "/boclouddeployerapi/cmpCluster/v2.4/createCluster", "failed",
                        JSONObject.toJSONString(messages), context);
                    ApplicationParam aplicaiton = JSONObject.parseObject(params.toJSONString(), ApplicationParam.class);
                    ServiceOrder order = aplicaiton.getOrder();
                    List<OrderItem> items = order.getItems();
                    List<QuotaBean> quotas = aplicaiton.getQuotas();
                    List<QuotaBean> beans = new ArrayList<>();
                    for (QuotaBean bean : quotas) {
                        beans.add(new QuotaBean(bean.getCode(), bean.getValue() / items.size()));
                    }
                    for (OrderItem item : items) {
                        // 通知订单修改订单状态
                        syncOrderStatus(item.getSn(), Operation.Application, "k8s虚拟机创建失败",
                            OrderItemStatus.OpenedFailure, context, null, beans, ResourceCategory.Kubernetes.name());
                    }
                }
            });
            return new BocloudResult<>(true, "任务已下发，正在执行...");
        } catch (Exception e) {
            this.callBoc(params.getString("callback"), new JSONObject(),
                "/boclouddeployerapi/cmpCluster/v2.4/createCluster", "failed", e.getMessage(), context);
            logger.error("Get error message：", e);
            return new BocloudResult<>(false, "创建失败");
        }
    }

    /**
     * 通知order 修改对应订单状态
     *
     * @param operation
     * @param message
     * @param status
     * @param context
     * @param newSn
     */
    private void syncOrderStatus(String uuid, OrderMessage.Operation operation, String message, OrderItemStatus status,
        RequestContext context, String newSn, List<QuotaBean> quotas, String category) {
        OrderMessage orderMessage =
            new OrderMessage(uuid, operation, status, null, message, null, null, new ArrayList<>(), category, context);
        orderMessage.setNewSn(newSn);
        orderMessage.setQuotas(quotas);
        amqpTemplate.convertAndSend("resource.result.queue", orderMessage);
    }

    /**
     * 保存k8s
     *
     * @param object
     * @param masters
     * @param nodes
     * @param nfss
     * @param context
     * @throws Exception
     */
    public void saveK8s(JSONObject object, List<JSONObject> masters, List<JSONObject> nodes, List<JSONObject> nfss,
        RequestContext context) throws Exception {
        ServiceOrder order = JSON.parseObject(object.getString("order"), ServiceOrder.class);
        List<OrderItem> items = order.getItems();
        if (ListTool.isEmpty(items)) {
            return;
        }
        JSONObject emption = JSONObject.parseObject(object.getString("emption"));
        // 使用时长信息
        JSONObject duration = JSONObject.parseObject(emption.getString("duration"));
        // 使用时长单位Hour/Month
        String mode = duration.getString("mode");
        // 时长
        Integer month = duration.getInteger("month");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        if ("Month".equalsIgnoreCase(mode)) {
            calendar.add(Calendar.MONTH, month);
        }
        JSONObject configs = object.getJSONObject("configs");
        JSONObject resource = analyze(object);
        Date date = new Date();
        for (int i = 0; i < items.size(); i++) {
            K8sCluster cluster = new K8sCluster();
            cluster.setName(configs.getString("name"));
            cluster.setStatus(Server.BUILDING.name());
            cluster.setCreatorId(context.getTarget());
            cluster.setTenantId(context.getTenant());
            cluster.setUuid(items.get(i).getSn());
            cluster.setInstanceId(IDFactory.instance().uuid());
            cluster.setType(configs.getString("category"));
            cluster.setRegion(resource.getString("region"));
            cluster.setInventory(object.toJSONString());
            cluster.setCategory(configs.getString("categoryCode"));
            cluster.setSkuId(configs.getLong("skuId"));
            cluster.setCategoryId(configs.getLong("categoryId"));
            JSONObject specs = new JSONObject();
            specs.put("cpu", resource.getString("cpu"));
            specs.put("memory", resource.getString("memory"));
            specs.put("disk", resource.getString("disk"));
            List<Integer> disks = JSONObject.parseArray(resource.getString("disks"), Integer.class);
            if (!ListTool.isEmpty(disks)) {
                specs.put("dataDisk", disks.get(0));
            }
            cluster.setSpec(specs.toJSONString());
            cluster.setGmtCreate(date);
            k8sClusterRepository.save(cluster);
            ObjectRelation relation = new ObjectRelation(context.getTarget(), cluster.getId(), false,
                ResourceCategory.Kubernetes.name(), context.getCatalog().name(), null);
            if ("Month".equalsIgnoreCase(mode)) {
                relation.setExpiredTime(calendar.getTime());
            }
            objectRelationRepository.save(relation);
            if (!ListTool.isEmpty(masters)) {
                for (JSONObject master : masters) {
                    K8sNode node = new K8sNode();
                    node.setName(master.getString("name"));
                    node.setRole("master");
                    node.setStatus(Server.RUNNING.name());
                    node.setInstanceId(master.getString("instanceId"));
                    node.setClusterId(cluster.getId());
                    node.setVendorId(master.getLong("vendorId"));
                    node.setUsername(master.getString("account"));
                    node.setPassword(master.getString("password"));
                    node.setSshPort(master.getInteger("port"));
                    node.setGmtCreate(date);
                    cluster.setSpec(specs.toJSONString());
                    k8sNodeRepository.save(node);
                }
            }
            if (!ListTool.isEmpty(nodes)) {
                for (JSONObject server : nodes) {
                    K8sNode node = new K8sNode();
                    node.setName(server.getString("name"));
                    node.setRole("node");
                    node.setStatus(Server.RUNNING.name());
                    node.setInstanceId(server.getString("instanceId"));
                    node.setClusterId(cluster.getId());
                    node.setVendorId(server.getLong("vendorId"));
                    node.setUsername(server.getString("account"));
                    node.setPassword(server.getString("password"));
                    node.setSshPort(server.getInteger("port"));
                    node.setGmtCreate(date);
                    cluster.setSpec(specs.toJSONString());
                    k8sNodeRepository.save(node);
                }
            }
            if (!ListTool.isEmpty(nfss)) {
                for (JSONObject server : nfss) {
                    K8sNode node = new K8sNode();
                    node.setName(server.getString("name"));
                    node.setRole("nfs");
                    node.setStatus(Server.RUNNING.name());
                    node.setInstanceId(server.getString("instanceId"));
                    node.setClusterId(cluster.getId());
                    node.setVendorId(server.getLong("vendorId"));
                    node.setUsername(server.getString("account"));
                    node.setPassword(server.getString("password"));
                    node.setSshPort(server.getInteger("port"));
                    node.setGmtCreate(date);
                    cluster.setSpec(specs.toJSONString());
                    k8sNodeRepository.save(node);
                }
            }
        }
    }

    public static JSONObject analyze(JSONObject object) {
        JSONObject params = new JSONObject();
        JSONObject location = object.getJSONObject("location");
        JSONObject resource = new JSONObject();
        resource.put("region", location.get("region"));
        resource.put("az", location.get("az"));
        resource.put("labels", location.get("labels"));
        JSONObject configs = object.getJSONObject("configs");
        resource.put("templateName", configs.get("templateName"));
        resource.put("vpcId", configs.get("vpcId"));
        resource.put("subnetId", configs.get("subnetId"));
        resource.put("diskCategory", configs.get("diskCategory"));
        List<JSONObject> skus = JSONArray.parseArray(object.getString("elements"), JSONObject.class);
        List<Integer> disks = new ArrayList<>();
        String serviceCode = object.getString("service");
        for (JSONObject sku : skus) {
            List<JSONObject> specs = JSONObject.parseArray(sku.getString("specs"), JSONObject.class);
            if (serviceCode.equals(sku.getString("serviceCode"))) {
                for (JSONObject spec : specs) {
                    if (spec.containsKey("cpu")) {
                        resource.put("cpu", spec.get("cpu"));
                    } else if (spec.containsKey("memory")) {
                        resource.put("memory", spec.get("memory"));
                    } else if (spec.containsKey("disk")) {
                        resource.put("disk", spec.get("disk"));
                    }
                }
                continue;
            }
            for (JSONObject spec : specs) {
                if (spec.containsKey("disk")) {
                    disks.add(spec.getIntValue("disk"));
                }
            }
        }
        resource.put("disks", disks);
        params.put("resource", resource);
        return params;
    }

    /**
     * 调用boc http://10.10.5.23:30022/boclouddeployerapi/cmpCluster/v2.4/createCluster
     *
     * @param callback
     * @param params
     * @param bocUrl
     * @param result
     *            success|failed
     * @param message
     * @return
     */
    private Result callBoc(String callback, JSONObject params, String bocUrl, String result, String message,
        RequestContext context) {
        String token = smsInternalService.getToken(context.getTarget(), context.getCatalog().name());
        logger.info("获取token：{}", token);
        HttpClient httpClient = new HttpClient(20 * 1000 * 1000, PostDataFormat.RAW);
        try {
            params.put("callback", callback);
            params.put("result", result);
            params.put("message", message);
            Map<String, Object> header = new HashMap<>();
            header.put("accept", "application/json");
            header.put("content-type", "application/json");
            if (!StringUtils.isEmpty(token)) {
                header.put("token", token);
            }
            String url = configService.getByCode("k8sAddress") + bocUrl;
            logger.info("调用boc地址：{}", url);
            logger.info("调用boc参数：{}", params.toJSONString());
            return httpClient.post(header, params, url);
        } catch (Exception e) {
            logger.error("Get error message：{}", e.getMessage());
            return Result.FAILED("回调容器平台失败");
        } finally {
            httpClient.close();
        }
    }

    @Override
    public BocloudResult createVip(String params, RequestContext context, String queue) {
        JSONObject object = JSONObject.parseObject(params);
        if (null == object) {
            send(queue, new BocloudResult<>(false, "VIP分配失败"));
            return ResultTools.formatErrResult();
        }
        try {
            JSONObject fronts = object.getJSONObject("fronts");
            BocloudResult<List<Ip>> ipResult = ipService.achieveDhcpIps(fronts.getLong("ipPoolId"), 1L, "V4");
            Assert.isTrue(ipResult.isSuccess(), ipResult.getMessage());
            List<Ip> ips = ipResult.getData();
            if (ListTool.isEmpty(ips)) {
                send(queue, new BocloudResult<>(false, "VIP分配失败"));
                return new BocloudResult<>(false, "VIP分配失败");
            }
            BocloudResult result = new BocloudResult<>(true, ips.get(0), "VIP分配成功");
            send(queue, result);
            return result;
        } catch (Exception e) {
            logger.error("Get error message：{}", e.getMessage());
            send(queue, new BocloudResult<>(false, "VIP分配失败"));
            return new BocloudResult<>(false, "VIP分配失败");
        }
    }

}
