package org.zstack.network.service.virtualrouter.lb; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.transaction.annotation.Transactional; import org.zstack.core.cloudbus.CloudBus; import org.zstack.core.cloudbus.CloudBusCallBack; import org.zstack.core.db.DatabaseFacade; import org.zstack.core.db.Q; import org.zstack.core.db.SQLBatch; import org.zstack.core.db.SimpleQuery; import org.zstack.core.db.SimpleQuery.Op; import org.zstack.core.errorcode.ErrorFacade; import org.zstack.core.timeout.ApiTimeoutManager; import org.zstack.core.workflow.FlowChainBuilder; import org.zstack.core.workflow.ShareFlow; import org.zstack.header.core.Completion; import org.zstack.header.core.ReturnValueCompletion; import org.zstack.header.core.workflow.*; import org.zstack.header.errorcode.ErrorCode; import org.zstack.header.errorcode.OperationFailureException; import org.zstack.header.exception.CloudRuntimeException; import org.zstack.header.message.MessageReply; import org.zstack.header.network.l3.L3NetworkInventory; import org.zstack.header.network.l3.L3NetworkVO; import org.zstack.header.tag.SystemTagVO; import org.zstack.header.tag.SystemTagVO_; import org.zstack.header.vm.*; import org.zstack.network.service.lb.*; import org.zstack.network.service.vip.*; import org.zstack.network.service.virtualrouter.*; import org.zstack.network.service.virtualrouter.VirtualRouterCommands.AgentCommand; import org.zstack.network.service.virtualrouter.VirtualRouterCommands.AgentResponse; import org.zstack.network.service.virtualrouter.vip.VirtualRouterVipBackend; import org.zstack.network.service.virtualrouter.vip.VirtualRouterVipVO; import org.zstack.network.service.virtualrouter.vip.VirtualRouterVipVO_; import org.zstack.tag.TagManager; import org.zstack.utils.CollectionUtils; import org.zstack.utils.DebugUtils; import org.zstack.utils.Utils; import org.zstack.utils.function.Function; import org.zstack.utils.logging.CLogger; import static org.zstack.core.Platform.operr; import javax.persistence.TypedQuery; import java.util.ArrayList; import java.util.List; import java.util.Map; import static org.zstack.utils.CollectionDSL.list; /** * Created by frank on 8/9/2015. */ public class VirtualRouterLoadBalancerBackend extends AbstractVirtualRouterBackend implements LoadBalancerBackend { private static CLogger logger = Utils.getLogger(VirtualRouterLoadBalancerBackend.class); @Autowired private DatabaseFacade dbf; @Autowired private CloudBus bus; @Autowired @Qualifier("VirtualRouterVipBackend") private VirtualRouterVipBackend vipVrBkd; @Autowired private VipManager vipMgr; @Autowired private ErrorFacade errf; @Autowired private TagManager tagMgr; @Autowired private ApiTimeoutManager apiTimeoutManager; @Transactional(readOnly = true) private VirtualRouterVmInventory findVirtualRouterVm(String lbUuid) { String sql = "select vr from VirtualRouterVmVO vr, VirtualRouterLoadBalancerRefVO ref where ref.virtualRouterVmUuid =" + " vr.uuid and ref.loadBalancerUuid = :lbUuid"; TypedQuery<VirtualRouterVmVO> q = dbf.getEntityManager().createQuery(sql, VirtualRouterVmVO.class); q.setParameter("lbUuid", lbUuid); List<VirtualRouterVmVO> vrs = q.getResultList(); return vrs.isEmpty() ? null : VirtualRouterVmInventory.valueOf(vrs.get(0)); } public static class LbTO { String lbUuid; String listenerUuid; String vip; List<String> nicIps; int instancePort; int loadBalancerPort; String mode; List<String> parameters; public String getListenerUuid() { return listenerUuid; } public void setListenerUuid(String listenerUuid) { this.listenerUuid = listenerUuid; } public List<String> getParameters() { return parameters; } public void setParameters(List<String> parameters) { this.parameters = parameters; } public String getLbUuid() { return lbUuid; } public void setLbUuid(String lbUuid) { this.lbUuid = lbUuid; } public String getVip() { return vip; } public void setVip(String vip) { this.vip = vip; } public List<String> getNicIps() { return nicIps; } public void setNicIps(List<String> nicIps) { this.nicIps = nicIps; } public int getInstancePort() { return instancePort; } public void setInstancePort(int instancePort) { this.instancePort = instancePort; } public int getLoadBalancerPort() { return loadBalancerPort; } public void setLoadBalancerPort(int loadBalancerPort) { this.loadBalancerPort = loadBalancerPort; } public String getMode() { return mode; } public void setMode(String mode) { this.mode = mode; } } public static class RefreshLbCmd extends AgentCommand { List<LbTO> lbs; public List<LbTO> getLbs() { return lbs; } public void setLbs(List<LbTO> lbs) { this.lbs = lbs; } } public static class RefreshLbRsp extends AgentResponse { } public static class DeleteLbCmd extends AgentCommand { List<LbTO> lbs; public List<LbTO> getLbs() { return lbs; } public void setLbs(List<LbTO> lbs) { this.lbs = lbs; } } public static class DeleteLbRsp extends AgentResponse { } public static final String REFRESH_LB_PATH = "/lb/refresh"; public static final String DELETE_LB_PATH = "/lb/delete"; private List<LbTO> makeLbTOs(final LoadBalancerStruct struct) { SimpleQuery<VipVO> q = dbf.createQuery(VipVO.class); q.select(VipVO_.ip); q.add(VipVO_.uuid, Op.EQ, struct.getLb().getVipUuid()); final String vip = q.findValue(); return CollectionUtils.transformToList(struct.getListeners(), new Function<LbTO, LoadBalancerListenerInventory>() { @Override public LbTO call(LoadBalancerListenerInventory l) { LbTO to = new LbTO(); to.setInstancePort(l.getInstancePort()); to.setLoadBalancerPort(l.getLoadBalancerPort()); to.setLbUuid(l.getLoadBalancerUuid()); to.setListenerUuid(l.getUuid()); to.setMode(l.getProtocol()); to.setVip(vip); to.setNicIps(CollectionUtils.transformToList(l.getVmNicRefs(), new Function<String, LoadBalancerListenerVmNicRefInventory>() { @Override public String call(LoadBalancerListenerVmNicRefInventory arg) { if (LoadBalancerVmNicStatus.Active.toString().equals(arg.getStatus()) || LoadBalancerVmNicStatus.Pending.toString().equals(arg.getStatus())) { VmNicInventory nic = struct.getVmNics().get(arg.getVmNicUuid()); if (nic == null) { throw new CloudRuntimeException(String.format("cannot find nic[uuid:%s]", arg.getVmNicUuid())); } return nic.getIp(); } return null; } })); SimpleQuery<SystemTagVO> q = dbf.createQuery(SystemTagVO.class); q.select(SystemTagVO_.tag); q.add(SystemTagVO_.resourceUuid, Op.EQ, l.getUuid()); q.add(SystemTagVO_.resourceType, Op.EQ, LoadBalancerListenerVO.class.getSimpleName()); List<String> tags = q.listValue(); to.setParameters(tags); return to; } }); } private void refresh(VirtualRouterVmInventory vr, LoadBalancerStruct struct, final Completion completion) { VirtualRouterAsyncHttpCallMsg msg = new VirtualRouterAsyncHttpCallMsg(); msg.setVmInstanceUuid(vr.getUuid()); msg.setPath(REFRESH_LB_PATH); RefreshLbCmd cmd = new RefreshLbCmd(); cmd.lbs = makeLbTOs(struct); msg.setCommand(cmd); msg.setCommandTimeout(apiTimeoutManager.getTimeout(cmd.getClass(), "30m")); bus.makeTargetServiceIdByResourceUuid(msg, VmInstanceConstant.SERVICE_ID, vr.getUuid()); bus.send(msg, new CloudBusCallBack(completion) { @Override public void run(MessageReply reply) { if (reply.isSuccess()) { RefreshLbRsp rsp = ((VirtualRouterAsyncHttpCallReply) reply).toResponse(RefreshLbRsp.class); if (rsp.isSuccess()) { completion.success(); } else { completion.fail(operr(rsp.getError())); } } else { completion.fail(reply.getError()); } } }); } private void startVrIfNeededAndRefresh(final VirtualRouterVmInventory vr, final LoadBalancerStruct struct, final Completion completion) { if (!VmInstanceState.Stopped.toString().equals(vr.getState())) { refresh(vr, struct, completion); return; } final VipInventory vip = VipInventory.valueOf(dbf.findByUuid(struct.getLb().getVipUuid(), VipVO.class)); final FlowChain chain = FlowChainBuilder.newShareFlowChain(); chain.setName(String.format("start-vr-%s-and-refresh-lb-%s", vr.getUuid(), struct.getLb().getUuid())); chain.then(new ShareFlow() { @Override public void setup() { flow(new NoRollbackFlow() { String __name__ = "start-vr"; @Override public void run(final FlowTrigger trigger, Map data) { StartVmInstanceMsg msg = new StartVmInstanceMsg(); msg.setVmInstanceUuid(vr.getUuid()); bus.makeTargetServiceIdByResourceUuid(msg, VmInstanceConstant.SERVICE_ID, vr.getUuid()); bus.send(msg, new CloudBusCallBack(trigger) { @Override public void run(MessageReply reply) { if (!reply.isSuccess()) { trigger.fail(reply.getError()); } else { trigger.next(); } } }); } }); flow(new Flow() { String __name__ = "create-vip-on-vr"; boolean success = false; @Override public void run(final FlowTrigger trigger, Map data) { SimpleQuery<VirtualRouterVipVO> q = dbf.createQuery(VirtualRouterVipVO.class); q.add(VirtualRouterVipVO_.uuid, Op.EQ, vip.getUuid()); q.add(VirtualRouterVipVO_.virtualRouterVmUuid, Op.EQ, vr.getUuid()); if (q.isExists()) { trigger.next(); return; } vipVrBkd.acquireVipOnVirtualRouterVm(vr, vip, new Completion(trigger) { @Override public void success() { success = true; trigger.next(); } @Override public void fail(ErrorCode errorCode) { trigger.fail(errorCode); } }); } @Override public void rollback(final FlowRollback trigger, Map data) { if (!success) { trigger.rollback(); return; } vipVrBkd.releaseVipOnVirtualRouterVm(vr, vip, new Completion(trigger) { @Override public void success() { trigger.rollback(); } @Override public void fail(ErrorCode errorCode) { logger.warn(String.format("failed to release vip[uuid:%s, ip:%s] on vr[uuid:%s], continue to rollback", vip.getUuid(), vip.getIp(), vr.getUuid())); trigger.rollback(); } }); } }); flow(new Flow() { String __name__ = "lock-vip"; UnmodifyVip rollback; @Override public void run(FlowTrigger trigger, Map data) { ModifyVipAttributesStruct s = new ModifyVipAttributesStruct(); s.setServiceProvider(VirtualRouterConstant.VIRTUAL_ROUTER_PROVIDER_TYPE); s.setPeerL3NetworkUuid(vr.getGuestNic().getL3NetworkUuid()); new Vip(struct.getLb().getVipUuid()).modify(s, new ReturnValueCompletion<UnmodifyVip>(trigger) { @Override public void success(UnmodifyVip ret) { rollback = ret; trigger.next(); } @Override public void fail(ErrorCode errorCode) { trigger.fail(errorCode); } }); } @Override public void rollback(FlowRollback trigger, Map data) { if (rollback == null) { trigger.rollback(); return; } rollback.unmodify(new Completion(trigger) { @Override public void success() { trigger.rollback(); } @Override public void fail(ErrorCode errorCode) { //TODO GC logger.warn(errorCode.toString()); trigger.rollback(); } }); } }); flow(new NoRollbackFlow() { String __name__ = "refresh-lb"; @Override public void run(final FlowTrigger trigger, Map data) { refresh(vr, struct, new Completion(trigger) { @Override public void success() { trigger.next(); } @Override public void fail(ErrorCode errorCode) { trigger.fail(errorCode); } }); } }); done(new FlowDoneHandler(completion) { @Override public void handle(Map data) { completion.success(); } }); error(new FlowErrorHandler(completion) { @Override public void handle(ErrorCode errCode, Map data) { completion.fail(errCode); } }); } }).start(); } @Override public void addVmNics(final LoadBalancerStruct struct, List<VmNicInventory> nics, final Completion completion) { VirtualRouterVmInventory vr = findVirtualRouterVm(struct.getLb().getUuid()); if (vr != null) { startVrIfNeededAndRefresh(vr, struct, completion); return; } VmNicInventory nic = nics.get(0); final L3NetworkInventory l3 = L3NetworkInventory.valueOf(dbf.findByUuid(nic.getL3NetworkUuid(), L3NetworkVO.class)); final VipInventory vip = VipInventory.valueOf(dbf.findByUuid(struct.getLb().getVipUuid(), VipVO.class)); DebugUtils.Assert(LoadBalancerConstants.LB_NETWORK_SERVICE_TYPE_STRING.equals(vip.getUseFor()), String.format("the vip[uuid:%s, name:%s, ip:%s, useFor: %s] is not for load balancer", vip.getUuid(), vip.getName(), vip.getIp(), vip.getUseFor())); final boolean separateVr = LoadBalancerSystemTags.SEPARATE_VR.hasTag(struct.getLb().getUuid()); FlowChain chain = FlowChainBuilder.newShareFlowChain(); chain.setName(String.format("add-nic-to-vr-lb-%s", struct.getLb().getUuid())); chain.then(new ShareFlow() { VirtualRouterVmInventory vr; @Override public void setup() { flow(new Flow() { String __name__ = "lock-vip"; boolean success = false; UnmodifyVip rollback; @Override public void run(FlowTrigger trigger, Map data) { ModifyVipAttributesStruct s = new ModifyVipAttributesStruct(); s.setPeerL3NetworkUuid(l3.getUuid()); s.setServiceProvider(VirtualRouterConstant.VIRTUAL_ROUTER_PROVIDER_TYPE); s.setUseFor(LoadBalancerConstants.LB_NETWORK_SERVICE_TYPE_STRING); new Vip(vip.getUuid()).modify(s, new ReturnValueCompletion<UnmodifyVip>(trigger) { @Override public void success(UnmodifyVip ret) { rollback = ret; trigger.next(); } @Override public void fail(ErrorCode errorCode) { trigger.fail(errorCode); } }); } @Override public void rollback(FlowRollback trigger, Map data) { if (!success) { trigger.rollback(); return; } rollback.unmodify(new Completion(trigger) { @Override public void success() { trigger.rollback(); } @Override public void fail(ErrorCode errorCode) { //TODO logger.warn(errorCode.toString()); trigger.rollback(); } }); } }); if (separateVr) { flow(new Flow() { String __name__ = "create-separate-vr"; @Override public void run(final FlowTrigger trigger, Map data) { VirtualRouterStruct s = new VirtualRouterStruct(); s.setInherentSystemTags(list(VirtualRouterSystemTags.DEDICATED_ROLE_VR.getTagFormat(), VirtualRouterSystemTags.VR_LB_ROLE.getTagFormat())); s.setVirtualRouterVmSelector(new VirtualRouterVmSelector() { @Override public VirtualRouterVmVO select(List<VirtualRouterVmVO> vrs) { return null; } }); s.setL3Network(l3); s.setNotGatewayForGuestL3Network(true); acquireVirtualRouterVm(s, new ReturnValueCompletion<VirtualRouterVmInventory>(trigger) { @Override public void success(VirtualRouterVmInventory returnValue) { vr = returnValue; new VirtualRouterRoleManager().makeLoadBalancerRole(vr.getUuid()); trigger.next(); } @Override public void fail(ErrorCode errorCode) { trigger.fail(errorCode); } }); } @Override public void rollback(final FlowRollback trigger, Map data) { if (vr == null) { trigger.rollback(); return; } DestroyVmInstanceMsg msg = new DestroyVmInstanceMsg(); msg.setVmInstanceUuid(vr.getUuid()); bus.makeTargetServiceIdByResourceUuid(msg, VmInstanceConstant.SERVICE_ID, vr.getUuid()); bus.send(msg, new CloudBusCallBack(trigger) { @Override public void run(MessageReply reply) { if (!reply.isSuccess()) { //TODO: logger.warn(String.format("failed to destroy vr[uuid:%s], %s. Need a cleanup", vr.getUuid(), reply.getError())); } trigger.rollback(); } }); } }); } else { flow(new NoRollbackFlow() { String __name__ = "acquire-vr"; @Override public void run(final FlowTrigger trigger, Map data) { VirtualRouterStruct s = new VirtualRouterStruct(); s.setL3Network(l3); acquireVirtualRouterVm(s, new ReturnValueCompletion<VirtualRouterVmInventory>(trigger) { @Override public void success(VirtualRouterVmInventory returnValue) { vr = returnValue; new VirtualRouterRoleManager().makeLoadBalancerRole(vr.getUuid()); trigger.next(); } @Override public void fail(ErrorCode errorCode) { trigger.fail(errorCode); } }); } }); } flow(new Flow() { String __name__ = "create-vip-on-vr"; boolean success = false; @Override public void run(final FlowTrigger trigger, Map data) { vipVrBkd.acquireVipOnVirtualRouterVm(vr, vip, new Completion(trigger) { @Override public void success() { success = true; trigger.next(); } @Override public void fail(ErrorCode errorCode) { trigger.fail(errorCode); } }); } @Override public void rollback(final FlowRollback trigger, Map data) { if (!success) { trigger.rollback(); return; } vipVrBkd.releaseVipOnVirtualRouterVm(vr, vip, new Completion(trigger) { @Override public void success() { trigger.rollback(); } @Override public void fail(ErrorCode errorCode) { logger.warn(String.format("failed to release vip[uuid:%s, ip:%s] on vr[uuid:%s], continue to rollback", vip.getUuid(), vip.getIp(), vr.getUuid())); trigger.rollback(); } }); } }); flow(new NoRollbackFlow() { String __name__ = "refresh-lb-on-vr"; @Override public void run(final FlowTrigger trigger, Map data) { refresh(vr, struct, new Completion(trigger) { @Override public void success() { trigger.next(); } @Override public void fail(ErrorCode errorCode) { trigger.fail(errorCode); } }); } }); done(new FlowDoneHandler(completion) { @Override public void handle(Map data) { new SQLBatch(){ @Override protected void scripts() { List<VirtualRouterLoadBalancerRefVO> refs = Q.New(VirtualRouterLoadBalancerRefVO.class) .eq(VirtualRouterLoadBalancerRefVO_.loadBalancerUuid,struct.getLb().getUuid()) .eq(VirtualRouterLoadBalancerRefVO_.virtualRouterVmUuid, vr.getUuid()).list(); if (refs.size() == 0) { VirtualRouterLoadBalancerRefVO ref = new VirtualRouterLoadBalancerRefVO(); ref.setLoadBalancerUuid(struct.getLb().getUuid()); ref.setVirtualRouterVmUuid(vr.getUuid()); persist(ref); } } }.execute(); completion.success(); } }); error(new FlowErrorHandler(completion) { @Override public void handle(ErrorCode errCode, Map data) { completion.fail(errCode); } }); } }).start(); } @Override public void addVmNic(final LoadBalancerStruct struct, VmNicInventory nic, final Completion completion) { addVmNics(struct, list(nic), completion); } @Override public void removeVmNic(LoadBalancerStruct struct, VmNicInventory nic, Completion completion) { removeVmNics(struct, list(nic), completion); } @Override public void removeVmNics(LoadBalancerStruct struct, List<VmNicInventory> nic, Completion completion) { VirtualRouterVmInventory vr = findVirtualRouterVm(struct.getLb().getUuid()); if (vr == null) { // the vr has been destroyed completion.success(); return; } if (VmInstanceState.Stopped.toString().equals(vr.getState())) { // no need to remove as the vr is stopped completion.success(); return; } refresh(vr, struct, completion); } @Override public void addListener(LoadBalancerStruct struct, LoadBalancerListenerInventory listener, Completion completion) { VirtualRouterVmInventory vr = findVirtualRouterVm(struct.getLb().getUuid()); if (vr == null) { throw new OperationFailureException(operr("cannot find virtual router for load balancer [uuid:%s]", struct.getLb().getUuid())); } startVrIfNeededAndRefresh(vr, struct, completion); } @Override public void removeListener(LoadBalancerStruct struct, LoadBalancerListenerInventory listener, Completion completion) { VirtualRouterVmInventory vr = findVirtualRouterVm(struct.getLb().getUuid()); if (vr == null) { // the vr has been destroyed completion.success(); return; } if (VmInstanceState.Stopped.toString().equals(vr.getState())) { completion.success(); return; } refresh(vr, struct, completion); } @Override public void destroyLoadBalancer(final LoadBalancerStruct struct, final Completion completion) { FlowChain chain = FlowChainBuilder.newShareFlowChain(); chain.setName(String.format("delete-lb-%s-from-vr", struct.getLb().getUuid())); chain.then(new ShareFlow() { @Override public void setup() { flow(new NoRollbackFlow() { String __name__ = "delete-from-vr"; @Override public void run(final FlowTrigger trigger, Map data) { VirtualRouterVmInventory vr = findVirtualRouterVm(struct.getLb().getUuid()); if (vr == null) { // the vr has been destroyed trigger.next(); return; } SimpleQuery<VirtualRouterLoadBalancerRefVO> q = dbf.createQuery(VirtualRouterLoadBalancerRefVO.class); q.add(VirtualRouterLoadBalancerRefVO_.loadBalancerUuid, Op.EQ, struct.getLb().getUuid()); q.add(VirtualRouterLoadBalancerRefVO_.virtualRouterVmUuid, Op.EQ, vr.getUuid()); final VirtualRouterLoadBalancerRefVO ref = q.find(); List<String> roles = new VirtualRouterRoleManager().getAllRoles(vr.getUuid()); if (roles.size() == 1 && roles.contains(VirtualRouterSystemTags.VR_LB_ROLE.getTagFormat())) { DestroyVmInstanceMsg msg = new DestroyVmInstanceMsg(); msg.setVmInstanceUuid(vr.getUuid()); bus.makeTargetServiceIdByResourceUuid(msg, VmInstanceConstant.SERVICE_ID, vr.getUuid()); bus.send(msg, new CloudBusCallBack(trigger) { @Override public void run(MessageReply reply) { if (reply.isSuccess()) { dbf.remove(ref); trigger.next(); } else { trigger.fail(reply.getError()); } } }); } else if (roles.size() > 1 && roles.contains(VirtualRouterSystemTags.VR_LB_ROLE.getTagFormat())) { DeleteLbCmd cmd = new DeleteLbCmd(); cmd.setLbs(makeLbTOs(struct)); VirtualRouterAsyncHttpCallMsg msg = new VirtualRouterAsyncHttpCallMsg(); msg.setVmInstanceUuid(vr.getUuid()); msg.setPath(DELETE_LB_PATH); msg.setCommand(cmd); msg.setCommandTimeout(apiTimeoutManager.getTimeout(cmd.getClass(), "30m")); bus.makeTargetServiceIdByResourceUuid(msg, VmInstanceConstant.SERVICE_ID, vr.getUuid()); bus.send(msg, new CloudBusCallBack(trigger) { @Override public void run(MessageReply reply) { if (reply.isSuccess()) { DeleteLbRsp rsp = ((VirtualRouterAsyncHttpCallReply)reply).toResponse(DeleteLbRsp.class); if (rsp.isSuccess()) { dbf.remove(ref); trigger.next(); } else { trigger.fail(operr(rsp.getError())); } } else { trigger.fail(reply.getError()); } } }); } else { throw new CloudRuntimeException(String.format("wrong virtual router roles%s. it doesn't have the role[%s]", roles, VirtualRouterSystemTags.VR_LB_ROLE.getTagFormat())); } } }); done(new FlowDoneHandler(completion) { @Override public void handle(Map data) { completion.success(); } }); error(new FlowErrorHandler(completion) { @Override public void handle(ErrorCode errCode, Map data) { completion.fail(errCode); } }); } }).start(); } @Override public void refresh(LoadBalancerStruct struct, Completion completion) { VirtualRouterVmInventory vr = findVirtualRouterVm(struct.getLb().getUuid()); if (vr == null) { // the vr has been destroyed completion.success(); return; } startVrIfNeededAndRefresh(vr, struct, completion); } void syncOnStart(VirtualRouterVmInventory vr, List<LoadBalancerStruct> structs, final Completion completion) { List<LbTO> tos = new ArrayList<LbTO>(); for (LoadBalancerStruct s : structs) { tos.addAll(makeLbTOs(s)); } RefreshLbCmd cmd = new RefreshLbCmd(); cmd.lbs = tos; VirtualRouterAsyncHttpCallMsg msg = new VirtualRouterAsyncHttpCallMsg(); msg.setCommand(cmd); msg.setCommandTimeout(apiTimeoutManager.getTimeout(cmd.getClass(), "30m")); msg.setPath(REFRESH_LB_PATH); msg.setVmInstanceUuid(vr.getUuid()); msg.setCheckStatus(false); bus.makeTargetServiceIdByResourceUuid(msg, VmInstanceConstant.SERVICE_ID, vr.getUuid()); bus.send(msg, new CloudBusCallBack(completion) { @Override public void run(MessageReply reply) { if (reply.isSuccess()) { VirtualRouterAsyncHttpCallReply kr = reply.castReply(); RefreshLbRsp rsp = kr.toResponse(RefreshLbRsp.class); if (rsp.isSuccess()) { completion.success(); } else { completion.fail(operr(rsp.getError())); } } else { completion.fail(reply.getError()); } } }); } @Override public String getNetworkServiceProviderType() { return VirtualRouterConstant.VIRTUAL_ROUTER_PROVIDER_TYPE; } }