package org.zstack.network.service.virtualrouter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.util.UriComponentsBuilder; import org.zstack.appliancevm.*; import org.zstack.core.CoreGlobalProperty; import org.zstack.core.Platform; import org.zstack.core.ansible.AnsibleFacade; import org.zstack.core.asyncbatch.While; import org.zstack.core.cloudbus.*; import org.zstack.core.componentloader.PluginRegistry; import org.zstack.core.db.*; import org.zstack.core.db.SimpleQuery.Op; import org.zstack.core.errorcode.ErrorFacade; import org.zstack.core.thread.ChainTask; import org.zstack.core.thread.SyncTaskChain; import org.zstack.core.thread.ThreadFacade; import org.zstack.core.workflow.FlowChainBuilder; import org.zstack.header.AbstractService; import org.zstack.header.apimediator.ApiMessageInterceptionException; import org.zstack.header.apimediator.GlobalApiMessageInterceptor; import org.zstack.header.configuration.APIUpdateInstanceOfferingEvent; import org.zstack.header.configuration.InstanceOfferingInventory; import org.zstack.header.configuration.InstanceOfferingState; import org.zstack.header.configuration.InstanceOfferingVO; import org.zstack.header.core.Completion; import org.zstack.header.core.FutureCompletion; import org.zstack.header.core.NoErrorCompletion; import org.zstack.header.core.ReturnValueCompletion; import org.zstack.header.core.workflow.Flow; import org.zstack.header.core.workflow.FlowChain; import org.zstack.header.core.workflow.WhileCompletion; import org.zstack.header.errorcode.ErrorCode; import org.zstack.header.errorcode.ErrorCodeList; import org.zstack.header.errorcode.OperationFailureException; import org.zstack.header.exception.CloudRuntimeException; import org.zstack.header.host.HypervisorType; import org.zstack.header.image.ImageInventory; import org.zstack.header.image.ImageVO; import org.zstack.header.managementnode.ManagementNodeReadyExtensionPoint; import org.zstack.header.managementnode.PrepareDbInitialValueExtensionPoint; import org.zstack.header.message.APICreateMessage; import org.zstack.header.message.APIMessage; import org.zstack.header.message.Message; import org.zstack.header.message.MessageReply; import org.zstack.header.network.NetworkException; import org.zstack.header.network.l2.APICreateL2NetworkMsg; import org.zstack.header.network.l2.L2NetworkConstant; import org.zstack.header.network.l2.L2NetworkCreateExtensionPoint; import org.zstack.header.network.l2.L2NetworkInventory; import org.zstack.header.network.l3.*; import org.zstack.header.network.service.*; import org.zstack.header.query.AddExpandedQueryExtensionPoint; import org.zstack.header.query.ExpandedQueryAliasStruct; import org.zstack.header.query.ExpandedQueryStruct; import org.zstack.header.tag.*; import org.zstack.header.vm.*; import org.zstack.identity.Account; import org.zstack.identity.AccountManager; import org.zstack.network.l3.IpRangeHelper; import org.zstack.network.l3.L3NetworkSystemTags; import org.zstack.network.service.NetworkServiceManager; import org.zstack.network.service.eip.EipConstant; import org.zstack.network.service.eip.FilterVmNicsForEipInVirtualRouterExtensionPoint; import org.zstack.network.service.eip.GetL3NetworkForEipInVirtualRouterExtensionPoint; import org.zstack.network.service.lb.*; import org.zstack.network.service.vip.*; import org.zstack.network.service.virtualrouter.eip.VirtualRouterEipRefInventory; import org.zstack.network.service.virtualrouter.ha.VirtualRouterHaBackend; import org.zstack.network.service.virtualrouter.lb.LbConfigProxy; import org.zstack.network.service.virtualrouter.portforwarding.VirtualRouterPortForwardingRuleRefInventory; import org.zstack.network.service.virtualrouter.vip.VipConfigProxy; import org.zstack.network.service.virtualrouter.vip.VirtualRouterVipInventory; import org.zstack.network.service.virtualrouter.vip.VirtualRouterVipVO; import org.zstack.network.service.virtualrouter.vip.VirtualRouterVipVO_; import org.zstack.network.service.virtualrouter.vyos.VyosConstants; import org.zstack.network.service.virtualrouter.vyos.VyosVersionCheckResult; import org.zstack.network.service.virtualrouter.vyos.VyosVersionManager; import org.zstack.tag.SystemTagCreator; import org.zstack.tag.TagManager; import org.zstack.utils.*; import org.zstack.utils.function.Function; import org.zstack.utils.logging.CLogger; import org.zstack.utils.network.NetworkUtils; import javax.persistence.TypedQuery; import java.util.*; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import static java.util.Arrays.asList; import static org.zstack.core.Platform.*; import static org.zstack.core.progress.ProgressReportService.createSubTaskProgress; import static org.zstack.network.service.virtualrouter.VirtualRouterConstant.VIRTUAL_ROUTER_PROVIDER_TYPE; import static org.zstack.network.service.virtualrouter.VirtualRouterNicMetaData.GUEST_NIC_MASK; import static org.zstack.network.service.virtualrouter.vyos.VyosConstants.VYOS_ROUTER_PROVIDER_TYPE; import static org.zstack.utils.CollectionDSL.e; import static org.zstack.utils.CollectionDSL.map; import static org.zstack.utils.VipUseForList.SNAT_NETWORK_SERVICE_TYPE; public class VirtualRouterManagerImpl extends AbstractService implements VirtualRouterManager, PrepareDbInitialValueExtensionPoint, L2NetworkCreateExtensionPoint, GlobalApiMessageInterceptor, AddExpandedQueryExtensionPoint, GetCandidateVmNicsForLoadBalancerExtensionPoint, GetPeerL3NetworksForLoadBalancerExtensionPoint, FilterVmNicsForEipInVirtualRouterExtensionPoint, ApvmCascadeFilterExtensionPoint, ManagementNodeReadyExtensionPoint, VipCleanupExtensionPoint, GetL3NetworkForEipInVirtualRouterExtensionPoint, VirtualRouterHaGetCallbackExtensionPoint { private final static CLogger logger = Utils.getLogger(VirtualRouterManagerImpl.class); private final static List<String> supportedL2NetworkTypes = new ArrayList<String>(); private NetworkServiceProviderInventory virtualRouterProvider; private Map<String, VirtualRouterHypervisorBackend> hypervisorBackends = new HashMap<String, VirtualRouterHypervisorBackend>(); private Map<String, Integer> vrParallelismDegrees = new ConcurrentHashMap<String, Integer>(); private List<String> virtualRouterPostCreateFlows; private List<String> virtualRouterPostStartFlows; private List<String> virtualRouterPostRebootFlows; private List<String> virtualRouterPostDestroyFlows; private List<String> virtualRouterReconnectFlows; private FlowChainBuilder postCreateFlowsBuilder; private FlowChainBuilder postStartFlowsBuilder; private FlowChainBuilder postRebootFlowsBuilder; private FlowChainBuilder postDestroyFlowsBuilder; private FlowChainBuilder reconnectFlowsBuilder; private List<VirtualRouterPostCreateFlowExtensionPoint> postCreateFlowExtensionPoints; private List<VirtualRouterPostStartFlowExtensionPoint> postStartFlowExtensionPoints; private List<VirtualRouterPostRebootFlowExtensionPoint> postRebootFlowExtensionPoints; private List<VirtualRouterPostReconnectFlowExtensionPoint> postReconnectFlowExtensionPoints; private List<VirtualRouterPostDestroyFlowExtensionPoint> postDestroyFlowExtensionPoints; private List<VipGetUsedPortRangeExtensionPoint> vipGetUsedPortRangeExtensionPoints; static { supportedL2NetworkTypes.add(L2NetworkConstant.L2_NO_VLAN_NETWORK_TYPE); supportedL2NetworkTypes.add(L2NetworkConstant.L2_VLAN_NETWORK_TYPE); } @Autowired private CloudBus bus; @Autowired private DatabaseFacade dbf; @Autowired private VirtualRouterProviderFactory providerFactory; @Autowired private PluginRegistry pluginRgty; @Autowired private AnsibleFacade asf; @Autowired private ErrorFacade errf; @Autowired private AccountManager acntMgr; @Autowired private ThreadFacade thdf; @Autowired private ApplianceVmFacade apvmf; @Autowired private TagManager tagMgr; @Autowired private NetworkServiceManager nwServiceMgr; @Autowired private VyosVersionManager vyosVersionManager; @Autowired private LbConfigProxy lbProxy; @Autowired private VipConfigProxy vipProxy; @Autowired protected VirutalRouterDefaultL3ConfigProxy defaultL3ConfigProxy; @Autowired private EventFacade evf; @Autowired private ResourceDestinationMaker destMaker; @Autowired protected VirtualRouterHaBackend haBackend; @Override @MessageSafe public void handleMessage(Message msg) { if (msg instanceof APIMessage) { handleApiMessage((APIMessage) msg); } else { handleLocalMessage(msg); } } private void handleLocalMessage(Message msg) { if (msg instanceof CreateVirtualRouterVmMsg) { handle((CreateVirtualRouterVmMsg) msg); } else if (msg instanceof CheckVirtualRouterVmVersionMsg) { handle((CheckVirtualRouterVmVersionMsg) msg); } else { bus.dealWithUnknownMessage(msg); } } private void handle(final CreateVirtualRouterVmMsg msg) { thdf.chainSubmit(new ChainTask(msg) { @Override public String getSyncSignature() { return String.format("create-vr-for-l3-%s", msg.getL3Network().getUuid()); } @Override public void run(final SyncTaskChain chain) { createVirtualRouter(msg, new NoErrorCompletion(msg, chain) { @Override public void done() { chain.next(); } }); } @Override public String getName() { return getSyncSignature(); } }); } private void createVirtualRouter(final CreateVirtualRouterVmMsg msg, final NoErrorCompletion completion) { final L3NetworkInventory l3Network = msg.getL3Network(); final VirtualRouterOfferingInventory offering = msg.getOffering(); final CreateVirtualRouterVmReply reply = new CreateVirtualRouterVmReply(); final String accountUuid = acntMgr.getOwnerAccountUuidOfResource(l3Network.getUuid()); class newVirtualRouterJob { private void failAndReply(ErrorCode err) { reply.setError(err); bus.reply(msg, reply); completion.done(); } private void openFirewall(ApplianceVmSpec aspec, String l3NetworkUuid, int port, ApplianceVmFirewallProtocol protocol) { ApplianceVmFirewallRuleInventory r = new ApplianceVmFirewallRuleInventory(); r.setL3NetworkUuid(l3NetworkUuid); r.setStartPort(port); r.setEndPort(port); r.setProtocol(protocol.toString()); aspec.getFirewallRules().add(r); } private void openAdditionalPorts(ApplianceVmSpec aspec, String mgmtNwUuid) { final List<String> tcpPorts = VirtualRouterGlobalProperty.TCP_PORTS_ON_MGMT_NIC; if (!tcpPorts.isEmpty()) { List<Integer> ports = CollectionUtils.transformToList(tcpPorts, new Function<Integer, String>() { @Override public Integer call(String arg) { return Integer.valueOf(arg); } }); for (int p : ports) { openFirewall(aspec, mgmtNwUuid, p, ApplianceVmFirewallProtocol.tcp); } } final List<String> udpPorts = VirtualRouterGlobalProperty.UDP_PORTS_ON_MGMT_NIC; if (!udpPorts.isEmpty()) { List<Integer> ports = CollectionUtils.transformToList(udpPorts, new Function<Integer, String>() { @Override public Integer call(String arg) { return Integer.valueOf(arg); } }); for (int p : ports) { openFirewall(aspec, mgmtNwUuid, p, ApplianceVmFirewallProtocol.udp); } } } private void checkIsIpRangeOverlap(){ String priStartIp; String priEndIp; String pubStartIp; String pubEndIp; L3NetworkVO pubL3Network = Q.New(L3NetworkVO.class).eq(L3NetworkVO_.uuid,msg.getOffering().getPublicNetworkUuid()).find(); List<IpRangeInventory> priIpranges = IpRangeHelper.getNormalIpRanges(l3Network); List<IpRangeInventory> pubIpranges = IpRangeHelper.getNormalIpRanges(pubL3Network); for(IpRangeInventory priIprange : priIpranges){ for(IpRangeInventory pubIprange : pubIpranges){ priStartIp = priIprange.getStartIp(); priEndIp = priIprange.getEndIp(); pubStartIp = pubIprange.getStartIp(); pubEndIp = pubIprange.getEndIp(); if(NetworkUtils.isIpv4RangeOverlap(priStartIp,priEndIp,pubStartIp,pubEndIp)){ throw new OperationFailureException(argerr("cannot create virtual Router vm while virtual router network overlaps with private network in ip ")); } } } } void create() { List<String> neededService = l3Network.getNetworkServiceTypesFromProvider(new Callable<String>() { @Override public String call() { SimpleQuery<NetworkServiceProviderVO> q = dbf.createQuery(NetworkServiceProviderVO.class); q.select(NetworkServiceProviderVO_.uuid); q.add(NetworkServiceProviderVO_.type, Op.EQ, msg.getProviderType()); return q.findValue(); } }.call()); if (neededService.contains(NetworkServiceType.SNAT.toString()) && offering.getPublicNetworkUuid() == null) { ErrorCode err = err(VirtualRouterErrors.NO_PUBLIC_NETWORK_IN_OFFERING, "L3Network[uuid:%s, name:%s] requires SNAT service, but default virtual router offering[uuid:%s, name:%s] doesn't have a public network", l3Network.getUuid(), l3Network.getName(), offering.getUuid(), offering.getName()); logger.warn(err.getDetails()); failAndReply(err); return; } checkIsIpRangeOverlap(); ImageVO imgvo = dbf.findByUuid(offering.getImageUuid(), ImageVO.class); final ApplianceVmSpec aspec = new ApplianceVmSpec(); aspec.setSyncCreate(false); aspec.setTemplate(ImageInventory.valueOf(imgvo)); aspec.setApplianceVmType(ApplianceVmType.valueOf(msg.getApplianceVmType())); aspec.setInstanceOffering(offering); aspec.setAccountUuid(accountUuid); aspec.setName(String.format("vrouter.l3.%s.%s", l3Network.getName(), l3Network.getUuid().substring(0, 6))); aspec.setInherentSystemTags(msg.getInherentSystemTags()); aspec.setSshUsername(VirtualRouterGlobalConfig.SSH_USERNAME.value()); aspec.setSshPort(VirtualRouterGlobalConfig.SSH_PORT.value(Integer.class)); aspec.setAgentPort(msg.getApplianceVmAgentPort()); L3NetworkInventory mgmtNw = L3NetworkInventory.valueOf(dbf.findByUuid(offering.getManagementNetworkUuid(), L3NetworkVO.class)); ApplianceVmNicSpec mgmtNicSpec = new ApplianceVmNicSpec(); mgmtNicSpec.setL3NetworkUuid(mgmtNw.getUuid()); mgmtNicSpec.setMetaData(VirtualRouterNicMetaData.MANAGEMENT_NIC_MASK.toString()); aspec.setManagementNic(mgmtNicSpec); String mgmtNwUuid = mgmtNw.getUuid(); String pnwUuid; // NOTE: don't open 22 port here; 22 port is default opened on mgmt network in virtual router with restricted rules // open 22 here will cause a non-restricted rule to be added openFirewall(aspec, mgmtNwUuid, VirtualRouterGlobalProperty.AGENT_PORT, ApplianceVmFirewallProtocol.tcp); openAdditionalPorts(aspec, mgmtNwUuid); if (offering.getPublicNetworkUuid() != null && !offering.getManagementNetworkUuid().equals(offering.getPublicNetworkUuid())) { L3NetworkInventory pnw = L3NetworkInventory.valueOf(dbf.findByUuid(offering.getPublicNetworkUuid(), L3NetworkVO.class)); ApplianceVmNicSpec pnicSpec = new ApplianceVmNicSpec(); pnicSpec.setL3NetworkUuid(pnw.getUuid()); pnicSpec.setMetaData(VirtualRouterNicMetaData.PUBLIC_NIC_MASK.toString()); aspec.getAdditionalNics().add(pnicSpec); pnwUuid = pnicSpec.getL3NetworkUuid(); aspec.setDefaultRouteL3Network(pnw); aspec.setDefaultL3Network(pnw); } else { // use management nic for both management and public mgmtNicSpec.setMetaData(VirtualRouterNicMetaData.PUBLIC_AND_MANAGEMENT_NIC_MASK.toString()); pnwUuid = mgmtNwUuid; aspec.setDefaultRouteL3Network(mgmtNw); aspec.setDefaultL3Network(mgmtNw); } if (!l3Network.getUuid().equals(mgmtNwUuid) && !l3Network.getUuid().equals(pnwUuid)) { ApplianceVmNicSpec nicSpec = new ApplianceVmNicSpec(); nicSpec.setL3NetworkUuid(l3Network.getUuid()); if ((L3NetworkSystemTags.ROUTER_INTERFACE_IP.hasTag(l3Network.getUuid()) || neededService.contains(NetworkServiceType.SNAT.toString())) && !msg.isNotGatewayForGuestL3Network()) { DebugUtils.Assert(!IpRangeHelper.getNormalIpRanges(l3Network).isEmpty(), String.format("how can l3Network[uuid:%s] doesn't have ip range", l3Network.getUuid())); IpRangeInventory ipr = IpRangeHelper.getNormalIpRanges(l3Network).get(0); nicSpec.setL3NetworkUuid(l3Network.getUuid()); nicSpec.setAcquireOnNetwork(false); nicSpec.setNetmask(ipr.getNetmask()); nicSpec.setIp(ipr.getGateway()); nicSpec.setGateway(ipr.getGateway()); } if (L3NetworkSystemTags.ROUTER_INTERFACE_IP.hasTag(l3Network.getUuid())) { nicSpec.setIp(L3NetworkSystemTags.ROUTER_INTERFACE_IP.getTokenByResourceUuid(l3Network.getUuid(), L3NetworkSystemTags.ROUTER_INTERFACE_IP_TOKEN)); } aspec.getAdditionalNics().add(nicSpec); } ApplianceVmNicSpec guestNicSpec = mgmtNicSpec.getL3NetworkUuid().equals(l3Network.getUuid()) ? mgmtNicSpec : CollectionUtils.find(aspec.getAdditionalNics(), new Function<ApplianceVmNicSpec, ApplianceVmNicSpec>() { @Override public ApplianceVmNicSpec call(ApplianceVmNicSpec arg) { return arg.getL3NetworkUuid().equals(l3Network.getUuid()) ? arg : null; } }); guestNicSpec.setMetaData(guestNicSpec.getMetaData() == null ? GUEST_NIC_MASK.toString() : String.valueOf(Integer.valueOf(guestNicSpec.getMetaData()) | GUEST_NIC_MASK)); if (neededService.contains(NetworkServiceType.DHCP.toString())) { openFirewall(aspec, l3Network.getUuid(), 68, ApplianceVmFirewallProtocol.udp); openFirewall(aspec, l3Network.getUuid(), 67, ApplianceVmFirewallProtocol.udp); } if (neededService.contains(NetworkServiceType.DNS.toString())) { openFirewall(aspec, l3Network.getUuid(), 53, ApplianceVmFirewallProtocol.udp); } logger.debug(String.format("unable to find running virtual for L3Network[name:%s, uuid:%s], is about to create a new one", l3Network.getName(), l3Network.getUuid())); apvmf.createApplianceVm(aspec, new ReturnValueCompletion<ApplianceVmInventory>(completion) { @Override public void success(ApplianceVmInventory apvm) { String paraDegree = VirtualRouterSystemTags.VR_OFFERING_PARALLELISM_DEGREE.getTokenByResourceUuid(offering.getUuid(), VirtualRouterSystemTags.PARALLELISM_DEGREE_TOKEN); if (paraDegree != null) { SystemTagCreator creator = VirtualRouterSystemTags.VR_PARALLELISM_DEGREE.newSystemTagCreator(apvm.getUuid()); creator.setTagByTokens(map(e( VirtualRouterSystemTags.PARALLELISM_DEGREE_TOKEN, paraDegree ))); creator.create(); } reply.setInventory(VirtualRouterVmInventory.valueOf(dbf.findByUuid(apvm.getUuid(), VirtualRouterVmVO.class))); bus.reply(msg, reply); completion.done(); } @Override public void fail(ErrorCode errorCode) { failAndReply(errorCode); } }); } } new newVirtualRouterJob().create(); } private void handleApiMessage(APIMessage msg) { if (msg instanceof APIUpdateVirtualRouterOfferingMsg) { handle((APIUpdateVirtualRouterOfferingMsg) msg); } else if (msg instanceof APIGetAttachablePublicL3ForVRouterMsg) { handle((APIGetAttachablePublicL3ForVRouterMsg) msg); } else if (msg instanceof APIGetVipUsedPortsMsg) { handle((APIGetVipUsedPortsMsg) msg); }else { bus.dealWithUnknownMessage(msg); } } private List<String> getVipUsedPortList(String vipUuid, String protocol){ List<String> useFor = Q.New(VipNetworkServicesRefVO.class).select(VipNetworkServicesRefVO_.serviceType).eq(VipNetworkServicesRefVO_.vipUuid, vipUuid).listValues(); VipUseForList useForList = new VipUseForList(useFor); List<RangeSet.Range> portRangeList = new ArrayList<RangeSet.Range>(); for (VipGetUsedPortRangeExtensionPoint ext : vipGetUsedPortRangeExtensionPoints) { RangeSet range = ext.getVipUsePortRange(vipUuid, protocol, useForList); portRangeList.addAll(range.getRanges()); } RangeSet portRange = new RangeSet(); portRange.setRanges(portRangeList); return portRange.sortAndToString(); } private void handle(APIGetVipUsedPortsMsg msg) { String vipUuid = msg.getUuid(); String protocl = msg.getProtocol().toUpperCase(); APIGetVipUsedPortsReply reply = new APIGetVipUsedPortsReply(); APIGetVipUsedPortsReply.VipPortRangeInventory inv = new APIGetVipUsedPortsReply.VipPortRangeInventory(); inv.setUuid(vipUuid); inv.setProtocol(protocl); inv.setUsedPorts(getVipUsedPortList(vipUuid, protocl)); reply.setInventories(Arrays.asList(inv)); bus.reply(msg, reply); } private void handle(APIGetAttachablePublicL3ForVRouterMsg msg) { APIGetAttachablePublicL3ForVRouterReply reply = new APIGetAttachablePublicL3ForVRouterReply(); List<L3NetworkVO> l3NetworkVOS = Q.New(L3NetworkVO.class).notEq(L3NetworkVO_.category, L3NetworkCategory.Private).list(); List<VmNicVO> vmNicVOS = Q.New(VmNicVO.class).eq(VmNicVO_.vmInstanceUuid, msg.getVmInstanceUuid()).list(); if (l3NetworkVOS == null || l3NetworkVOS.isEmpty()) { reply.setInventories(new ArrayList<L3NetworkInventory>()); bus.reply(msg, reply); return; } Set<L3NetworkVO> attachableL3NetworkVOS = new HashSet<>(l3NetworkVOS); for (L3NetworkVO l3NetworkVO : l3NetworkVOS) { List<IpRangeInventory> iprs = IpRangeHelper.getNormalIpRanges(l3NetworkVO); for (VmNicVO vmNicVO : vmNicVOS) { if (iprs.isEmpty()) { attachableL3NetworkVOS.remove(l3NetworkVO); } String vmNicCidr = NetworkUtils.getCidrFromIpMask(vmNicVO.getIp(), vmNicVO.getNetmask()); if (!iprs.isEmpty() && NetworkUtils.isCidrOverlap(iprs.stream().findFirst().get().getNetworkCidr(), vmNicCidr)) { attachableL3NetworkVOS.remove(l3NetworkVO); } attachableL3NetworkVOS.removeAll(attachableL3NetworkVOS.stream() .filter(vo -> vo.getUuid().equals(vmNicVO.getL3NetworkUuid())) .collect(Collectors.toSet())); } } reply.setInventories(L3NetworkInventory.valueOf(attachableL3NetworkVOS)); bus.reply(msg, reply); } private void handle(APIUpdateVirtualRouterOfferingMsg msg) { VirtualRouterOfferingVO ovo = dbf.findByUuid(msg.getUuid(), VirtualRouterOfferingVO.class); boolean updated = false; if (msg.getName() != null) { ovo.setName(msg.getName()); updated = true; } if (msg.getDescription() != null) { ovo.setDescription(msg.getDescription()); updated = true; } if (msg.getImageUuid() != null) { ovo.setImageUuid(msg.getImageUuid()); updated = true; } if (updated) { ovo = dbf.updateAndRefresh(ovo); } if (msg.getIsDefault() != null) { DefaultVirtualRouterOfferingSelector selector = new DefaultVirtualRouterOfferingSelector(); selector.setZoneUuid(ovo.getZoneUuid()); selector.setPreferToBeDefault(msg.getIsDefault()); selector.setOfferingUuid(ovo.getUuid()); selector.selectDefaultOffering(); } APIUpdateInstanceOfferingEvent evt = new APIUpdateInstanceOfferingEvent(msg.getId()); evt.setInventory(VirtualRouterOfferingInventory.valueOf(dbf.reload(ovo))); bus.publish(evt); } @Override public String getId() { return bus.makeLocalServiceId(VirtualRouterConstant.SERVICE_ID); } private void rebootVirtualRouterVmOnRebootEvent() { evf.on(VmCanonicalEvents.VM_LIBVIRT_REPORT_REBOOT, new EventCallback<Object>() { @Override protected void run(Map<String, String> tokens, Object data) { String vmUuid = (String) data; VirtualRouterVmVO vrVO = dbf.findByUuid(vmUuid, VirtualRouterVmVO.class); if (vrVO == null) { return; } if (!destMaker.isManagedByUs(vmUuid)) { return; } RebootVmInstanceMsg msg = new RebootVmInstanceMsg(); msg.setVmInstanceUuid(vmUuid); bus.makeTargetServiceIdByResourceUuid(msg, VmInstanceConstant.SERVICE_ID, vmUuid); bus.send(msg); } }); } @Override public boolean start() { populateExtensions(); deployAnsible(); buildWorkFlowBuilder(); installSystemValidator(); rebootVirtualRouterVmOnRebootEvent(); VirtualRouterSystemTags.VR_PARALLELISM_DEGREE.installLifeCycleListener(new SystemTagLifeCycleListener() { @Override public void tagCreated(SystemTagInventory tag) { if (VirtualRouterSystemTags.VR_PARALLELISM_DEGREE.isMatch(tag.getTag())) { String value = VirtualRouterSystemTags.VR_PARALLELISM_DEGREE.getTokenByTag(tag.getTag(), VirtualRouterSystemTags.PARALLELISM_DEGREE_TOKEN); vrParallelismDegrees.put(tag.getResourceUuid(), Integer.valueOf(value)); } } @Override public void tagDeleted(SystemTagInventory tag) { if (VirtualRouterSystemTags.VR_PARALLELISM_DEGREE.isMatch(tag.getTag())) { vrParallelismDegrees.remove(tag.getResourceUuid()); } } @Override public void tagUpdated(SystemTagInventory old, SystemTagInventory newTag) { } }); return true; } @Override public boolean stop() { return true; } private void installSystemValidator() { class VirtualRouterOfferingValidator implements SystemTagCreateMessageValidator, SystemTagValidator { @Override public void validateSystemTagInCreateMessage(APICreateMessage msg) { if (msg instanceof APICreateL3NetworkMsg) { validate((APICreateL3NetworkMsg) msg); } } private void validate(APICreateL3NetworkMsg msg) { for (String sysTag : msg.getSystemTags()) { if (VirtualRouterSystemTags.VIRTUAL_ROUTER_OFFERING.isMatch(sysTag)) { validateVirtualRouterOffering(sysTag, msg.getResourceUuid()); } } } private void validateVirtualRouterOffering(String sysTag, String resourceUuid) { String offeringUuid = VirtualRouterSystemTags.VIRTUAL_ROUTER_OFFERING.getTokenByTag(sysTag, VirtualRouterSystemTags.VIRTUAL_ROUTER_OFFERING_TOKEN); VirtualRouterOfferingVO offeringVO = dbf.findByUuid(offeringUuid, VirtualRouterOfferingVO.class); if (offeringVO == null) { throw new ApiMessageInterceptionException(argerr("No virtual router instance offering with uuid:%s is found", offeringUuid)); } if (resourceUuid != null && resourceUuid.equals(offeringVO.getPublicNetworkUuid())) { throw new ApiMessageInterceptionException(argerr("the network of virtual router instance offering with uuid:%s can't be same with private l3 network uuid:%s", offeringUuid, resourceUuid)); } } @Override public void validateSystemTag(String resourceUuid, Class resourceType, String systemTag) { if (VirtualRouterSystemTags.VIRTUAL_ROUTER_OFFERING.isMatch(systemTag)) { validateVirtualRouterOffering(systemTag, resourceUuid); } } } class VirtualRouterOfferingOperator implements SystemTagResourceDeletionOperator { @Override public void execute(Collection resourceUuids) { List<String> tags = (List<String>) resourceUuids.stream().map(resourceUuid -> TagUtils.tagPatternToSqlPattern(VirtualRouterSystemTags.VIRTUAL_ROUTER_OFFERING.instantiateTag( map(e(VirtualRouterSystemTags.VIRTUAL_ROUTER_OFFERING_TOKEN, resourceUuid))))).collect(Collectors.toList()); SQL.New(SystemTagVO.class).in(SystemTagVO_.tag, tags).delete(); } } VirtualRouterOfferingValidator validator = new VirtualRouterOfferingValidator(); tagMgr.installCreateMessageValidator(L3NetworkVO.class.getSimpleName(), validator); tagMgr.installAfterResourceDeletionOperator(InstanceOfferingVO.class.getSimpleName(), new VirtualRouterOfferingOperator()); VirtualRouterSystemTags.VIRTUAL_ROUTER_OFFERING.installValidator(validator); } @Transactional private void prepareDbInitialValueForPublicVip() { /* vip upgrade for multiple public interface */ List<VipVO> vips = new ArrayList<>(); List<VirtualRouterVipVO> vvips = new ArrayList<>(); List<VirtualRouterVmVO> vrVos = Q.New(VirtualRouterVmVO.class).list(); for (VirtualRouterVmVO vr : vrVos) { if (vr.getDefaultL3NetworkUuid() == null) { SQL.New(VirtualRouterVmVO.class).eq(VirtualRouterVmVO_.uuid, vr.getUuid()) .set(VirtualRouterVmVO_.defaultL3NetworkUuid, vr.getPublicNetworkUuid()).update(); } if (vr.isHaEnabled()) { continue; } /* create public vip for additional public nic */ VirtualRouterVmInventory vrInv = VirtualRouterVmInventory.valueOf(vr); for (VmNicInventory nic : vrInv.getAdditionalPublicNics()) { if (Q.New(VipVO.class).eq(VipVO_.ip, nic.getIp()).eq(VipVO_.l3NetworkUuid, nic.getL3NetworkUuid()).isExists()) { continue; } L3NetworkInventory vipL3 = L3NetworkInventory.valueOf(dbf.findByUuid(nic.getL3NetworkUuid(), L3NetworkVO.class)); IpRangeInventory ipRange = null; for (IpRangeInventory ipr : IpRangeHelper.getNormalIpRanges(vipL3)) { if (NetworkUtils.isIpv4InRange(nic.getIp(), ipr.getStartIp(), ipr.getEndIp())) { ipRange = ipr; break; } } if (ipRange == null){ logger.warn(String.format("can not find ip range for ip address[ip:%s, l3 network: Uuid]", nic.getIp(), nic.getL3NetworkUuid())); continue; } if (nic.getUsedIpUuid() == null) { logger.warn(String.format("usedIpUuid of vmnic [Uuid:%s] is NULL", nic.getUuid())); continue; } VipVO vipvo = new VipVO(); vipvo.setUuid(Platform.getUuid()); vipvo.setName(String.format("vip-%s", vr.getName())); vipvo.setDescription(String.format("system vip for %s", vr.getName())); vipvo.setState(VipState.Enabled); vipvo.setGateway(nic.getGateway()); vipvo.setIp(nic.getIp()); vipvo.setIpRangeUuid(ipRange.getUuid()); vipvo.setL3NetworkUuid(nic.getL3NetworkUuid()); vipvo.setNetmask(nic.getNetmask()); vipvo.setUsedIpUuid(nic.getUsedIpUuid()); vipvo.setAccountUuid(Account.getAccountUuidOfResource(vr.getUuid())); vipvo.setSystem(true); vipvo.setPrefixLen(ipRange.getPrefixLen()); vipvo.setServiceProvider(VyosConstants.PROVIDER_TYPE.toString()); vips.add(vipvo); VirtualRouterVipVO vvip = new VirtualRouterVipVO(); vvip.setVirtualRouterVmUuid(vrInv.getUuid()); vvip.setUuid(vipvo.getUuid()); vvips.add(vvip); } } if (!vips.isEmpty()) { dbf.persistCollection(vips); } if (!vvips.isEmpty()) { dbf.persistCollection(vvips); } } public void prepareDbInitialValue() { prepareDbInitialValueForPublicVip(); SimpleQuery<NetworkServiceProviderVO> query = dbf.createQuery(NetworkServiceProviderVO.class); query.add(NetworkServiceProviderVO_.type, Op.EQ, VIRTUAL_ROUTER_PROVIDER_TYPE); NetworkServiceProviderVO rpvo = query.find(); if (rpvo != null) { virtualRouterProvider = NetworkServiceProviderInventory.valueOf(rpvo); return; } NetworkServiceProviderVO vo = new NetworkServiceProviderVO(); vo.setUuid(Platform.getUuid()); vo.setName(VIRTUAL_ROUTER_PROVIDER_TYPE); vo.setDescription("zstack virtual router network service provider"); vo.getNetworkServiceTypes().add(NetworkServiceType.DHCP.toString()); vo.getNetworkServiceTypes().add(NetworkServiceType.DNS.toString()); vo.getNetworkServiceTypes().add(NetworkServiceType.SNAT.toString()); vo.getNetworkServiceTypes().add(NetworkServiceType.PortForwarding.toString()); vo.getNetworkServiceTypes().add(EipConstant.EIP_NETWORK_SERVICE_TYPE); vo.getNetworkServiceTypes().add(LoadBalancerConstants.LB_NETWORK_SERVICE_TYPE_STRING); vo.setType(VIRTUAL_ROUTER_PROVIDER_TYPE); vo = dbf.persistAndRefresh(vo); virtualRouterProvider = NetworkServiceProviderInventory.valueOf(vo); } private void populateExtensions() { for (VirtualRouterHypervisorBackend extp : pluginRgty.getExtensionList(VirtualRouterHypervisorBackend.class)) { VirtualRouterHypervisorBackend old = hypervisorBackends.get(extp.getVirtualRouterSupportedHypervisorType().toString()); if (old != null) { throw new CloudRuntimeException(String.format("duplicate VirtualRouterHypervisorBackend[%s, %s] for type[%s]", extp.getClass().getName(), old.getClass().getName(), old.getVirtualRouterSupportedHypervisorType())); } hypervisorBackends.put(extp.getVirtualRouterSupportedHypervisorType().toString(), extp); } postCreateFlowExtensionPoints = pluginRgty.getExtensionList(VirtualRouterPostCreateFlowExtensionPoint.class); postStartFlowExtensionPoints = pluginRgty.getExtensionList(VirtualRouterPostStartFlowExtensionPoint.class); postRebootFlowExtensionPoints = pluginRgty.getExtensionList(VirtualRouterPostRebootFlowExtensionPoint.class); postReconnectFlowExtensionPoints = pluginRgty.getExtensionList(VirtualRouterPostReconnectFlowExtensionPoint.class); postDestroyFlowExtensionPoints = pluginRgty.getExtensionList(VirtualRouterPostDestroyFlowExtensionPoint.class); vipGetUsedPortRangeExtensionPoints = pluginRgty.getExtensionList(VipGetUsedPortRangeExtensionPoint.class); } private NetworkServiceProviderVO getRouterVO() { SimpleQuery<NetworkServiceProviderVO> query = dbf.createQuery(NetworkServiceProviderVO.class); query.add(NetworkServiceProviderVO_.type, Op.EQ, VIRTUAL_ROUTER_PROVIDER_TYPE); return query.find(); } @Override public void beforeCreateL2Network(APICreateL2NetworkMsg msg) throws NetworkException { } @Override public void afterCreateL2Network(L2NetworkInventory l2Network) { if (!supportedL2NetworkTypes.contains(l2Network.getType())) { return; } NetworkServiceProviderVO vo = getRouterVO(); NetworkServiceProvider router = providerFactory.getNetworkServiceProvider(vo); try { router.attachToL2Network(l2Network, null); } catch (NetworkException e) { String err = String.format("unable to attach network service provider[uuid:%s, name:%s, type:%s] to l2network[uuid:%s, name:%s, type:%s], %s", vo.getUuid(), vo.getName(), vo.getType(), l2Network.getUuid(), l2Network.getName(), l2Network.getType(), e.getMessage()); logger.warn(err, e); return; } NetworkServiceProviderL2NetworkRefVO ref = new NetworkServiceProviderL2NetworkRefVO(); ref.setNetworkServiceProviderUuid(vo.getUuid()); ref.setL2NetworkUuid(l2Network.getUuid()); dbf.persist(ref); String info = String.format("successfully attach network service provider[uuid:%s, name:%s, type:%s] to l2network[uuid:%s, name:%s, type:%s]", vo.getUuid(), vo.getName(), vo.getType(), l2Network.getUuid(), l2Network.getName(), l2Network.getType()); logger.debug(info); } private void deployAnsible() { if (CoreGlobalProperty.UNIT_TEST_ON) { return; } asf.deployModule(VirtualRouterConstant.ANSIBLE_MODULE_PATH, VirtualRouterConstant.ANSIBLE_PLAYBOOK_NAME); } @Override public VirtualRouterHypervisorBackend getHypervisorBackend(HypervisorType hypervisorType) { VirtualRouterHypervisorBackend b = hypervisorBackends.get(hypervisorType.toString()); if (b == null) { throw new CloudRuntimeException(String.format("unable to find VirtualRouterHypervisorBackend for hypervisorType[%s]", hypervisorType)); } return b; } @Override public String buildUrl(String mgmtNicIp, String subPath) { UriComponentsBuilder ub = UriComponentsBuilder.newInstance(); ub.scheme(VirtualRouterGlobalProperty.AGENT_URL_SCHEME); if (CoreGlobalProperty.UNIT_TEST_ON) { ub.host("localhost"); } else { ub.host(mgmtNicIp); } ub.port(VirtualRouterGlobalProperty.AGENT_PORT); if (!"".equals(VirtualRouterGlobalProperty.AGENT_URL_ROOT_PATH)) { ub.path(VirtualRouterGlobalProperty.AGENT_URL_ROOT_PATH); } ub.path(subPath); return ub.build().toUriString(); } private void buildWorkFlowBuilder() { postCreateFlowsBuilder = FlowChainBuilder.newBuilder().setFlowClassNames(virtualRouterPostCreateFlows).construct(); postStartFlowsBuilder = FlowChainBuilder.newBuilder().setFlowClassNames(virtualRouterPostStartFlows).construct(); postRebootFlowsBuilder = FlowChainBuilder.newBuilder().setFlowClassNames(virtualRouterPostRebootFlows).construct(); postDestroyFlowsBuilder = FlowChainBuilder.newBuilder().setFlowClassNames(virtualRouterPostDestroyFlows).construct(); reconnectFlowsBuilder = FlowChainBuilder.newBuilder().setFlowClassNames(virtualRouterReconnectFlows).construct(); } @Override public List<String> selectL3NetworksNeedingSpecificNetworkService(List<String> candidate, NetworkServiceType nsType) { if (candidate == null || candidate.isEmpty()) { return new ArrayList<>(0); } // need to specify provider type due to that the provider might be Flat return SQL.New("select ref.l3NetworkUuid from NetworkServiceL3NetworkRefVO ref, NetworkServiceProviderVO nspv" + " where ref.l3NetworkUuid in (:candidate) and ref.networkServiceType = :stype" + " and nspv.uuid = ref.networkServiceProviderUuid and nspv.type in (:ntype)") .param("candidate", candidate) .param("stype", nsType.toString()) .param("ntype", asList(VIRTUAL_ROUTER_PROVIDER_TYPE, VYOS_ROUTER_PROVIDER_TYPE)) .list(); } @Override public List<String> selectGuestL3NetworksNeedingSpecificNetworkService(List<String> candidate, NetworkServiceType nsType, String publicUuid) { List<String> ret = selectL3NetworksNeedingSpecificNetworkService(candidate, nsType); if (ret.isEmpty()) { return new ArrayList<>(); } /*get guest L3 includes two parts: 1. the virtual router all guest networks 2. flat networks both attached with nsType services and a virtualrouter offer */ /* step 1: get the offerings that public network is publicuuid step 2: get all the guest networks that has attached with these offerings */ List<String > offeringUuids = Q.New(VirtualRouterOfferingVO.class).eq(VirtualRouterOfferingVO_.publicNetworkUuid, publicUuid) .eq(VirtualRouterOfferingVO_.state, InstanceOfferingState.Enabled) .select(VirtualRouterOfferingVO_.uuid).listValues(); if (offeringUuids.isEmpty()) { /*public network is same with that of backend server*/ if (ret.contains(publicUuid)) { return Arrays.asList(publicUuid); } else { return new ArrayList<>(); } } return ret.stream().filter(l3 -> { L3NetworkVO l3Vo = dbf.findByUuid(l3, L3NetworkVO.class); if ( !l3Vo.getType().equals(L3NetworkConstant.L3_BASIC_NETWORK_TYPE)) { return false; } if (l3Vo.getNetworkServices().stream().filter(service -> VirtualRouterConstant.SNAT_NETWORK_SERVICE_TYPE.equals(service.getNetworkServiceType())).count() > 0l) { /*virtual networks*/ List<VirtualRouterOfferingInventory> offeringInventories = findOfferingByGuestL3Network(L3NetworkInventory.valueOf(l3Vo)); if (offeringInventories == null | offeringInventories.isEmpty()) { return false; } return l3.equals(publicUuid) || !offeringInventories.stream().filter(it -> offeringUuids.contains(it.getUuid())).collect(Collectors.toList()).isEmpty(); } else { /*flat private network*/ /*List<String> offer = Q.New(SystemTagVO.class). eq(SystemTagVO_.tag, VirtualRouterSystemTags.VR_OFFERING_GUEST_NETWORK.instantiateTag(map(e(VirtualRouterSystemTags.VR_OFFERING_GUEST_NETWORK_TOKEN, l3)))) .select(SystemTagVO_.resourceUuid).eq(SystemTagVO_.resourceType, InstanceOfferingVO.class.getSimpleName()) .in(SystemTagVO_.resourceUuid, offeringUuids) .listValues(); return !offer.isEmpty();*/ List<String> offer = VirtualRouterSystemTags.VIRTUAL_ROUTER_OFFERING.getTokensOfTagsByResourceUuid(l3) .stream().map(tokens -> tokens.get(VirtualRouterSystemTags.VIRTUAL_ROUTER_OFFERING_TOKEN)).collect(Collectors.toList()); if (offer == null | offer.isEmpty()) { return false; } return l3.equals(publicUuid) || !offer.stream().filter(uuid -> offeringUuids.contains(uuid)).collect(Collectors.toList()).isEmpty(); } }).collect(Collectors.toList()); } @Override public boolean isL3NetworkNeedingNetworkServiceByVirtualRouter(String l3Uuid, String nsType) { if (l3Uuid == null) { return false; } SimpleQuery<NetworkServiceL3NetworkRefVO> q = dbf.createQuery(NetworkServiceL3NetworkRefVO.class); q.add(NetworkServiceL3NetworkRefVO_.l3NetworkUuid, Op.EQ, l3Uuid); q.add(NetworkServiceL3NetworkRefVO_.networkServiceType, Op.EQ, nsType); // no need to specify provider type, L3 networks identified by candidates are served by virtual router or vyos return q.isExists(); } @Override public boolean isL3NetworksNeedingNetworkServiceByVirtualRouter(List<String> l3Uuids, String nsType) { if (l3Uuids == null || l3Uuids.isEmpty()) { return false; } SimpleQuery<NetworkServiceL3NetworkRefVO> q = dbf.createQuery(NetworkServiceL3NetworkRefVO.class); q.add(NetworkServiceL3NetworkRefVO_.l3NetworkUuid, Op.IN, l3Uuids); q.add(NetworkServiceL3NetworkRefVO_.networkServiceType, Op.EQ, nsType); // no need to specify provider type, L3 networks identified by candidates are served by virtual router or vyos return q.isExists(); } private void acquireVirtualRouterVmInternal(VirtualRouterStruct struct, final ReturnValueCompletion<VirtualRouterVmInventory> completion) { final L3NetworkInventory l3Nw = struct.getL3Network(); final VirtualRouterOfferingValidator validator = struct.getOfferingValidator(); final VirtualRouterVmSelector selector = struct.getVirtualRouterVmSelector(); VirtualRouterVmInventory vr = new Callable<VirtualRouterVmInventory>() { @Transactional(readOnly = true) private VirtualRouterVmVO findVR() { String sql = "select vr from VirtualRouterVmVO vr, VmNicVO nic where vr.uuid = nic.vmInstanceUuid and nic.l3NetworkUuid = :l3Uuid and nic.metaData in (:guestMeta)"; TypedQuery<VirtualRouterVmVO> q = dbf.getEntityManager().createQuery(sql, VirtualRouterVmVO.class); q.setParameter("l3Uuid", l3Nw.getUuid()); q.setParameter("guestMeta", VirtualRouterNicMetaData.GUEST_NIC_MASK_STRING_LIST); List<VirtualRouterVmVO> vrs = q.getResultList(); if (vrs.isEmpty()) { return null; } /* if there is master, return master */ for (VirtualRouterVmVO vo : vrs) { if (ApplianceVmHaStatus.Master == vo.getHaStatus()) { return vo; } } if (selector == null) { return findTheEarliestOne(vrs); } else { return selector.select(vrs); } } private VirtualRouterVmVO findTheEarliestOne(List<VirtualRouterVmVO> vrs) { VirtualRouterVmVO vr = null; for (VirtualRouterVmVO v : vrs) { if (vr == null) { vr = v; continue; } vr = vr.getCreateDate().before(v.getCreateDate()) ? vr : v; } return vr; } @Override public VirtualRouterVmInventory call() { VirtualRouterVmVO vr = findVR(); return vr == null ? null : new VirtualRouterVmInventory(vr); } }.call(); if (vr != null) { ErrorCodeList errorCodeList = new ErrorCodeList(); new While<>(pluginRgty.getExtensionList(AfterAcquireVirtualRouterExtensionPoint.class)).each((ext, c) -> { ext.afterAcquireVirtualRouter(vr, new Completion(c) { @Override public void success() { c.done(); } @Override public void fail(ErrorCode errorCode) { errorCodeList.getCauses().add(errorCode); c.done(); } }); }).run(new NoErrorCompletion(completion) { @Override public void done() { if (!errorCodeList.getCauses().isEmpty()) { completion.fail(errorCodeList.getCauses().get(0)); return; } VirtualRouterVmVO vo = dbf.findByUuid(vr.getUuid(), VirtualRouterVmVO.class); completion.success(VirtualRouterVmInventory.valueOf(vo)); } }); return; } List<VirtualRouterOfferingInventory> offerings = findOfferingByGuestL3Network(l3Nw); if (offerings == null) { ErrorCode err = err(VirtualRouterErrors.NO_DEFAULT_OFFERING, "unable to find a virtual router offering for l3Network[uuid:%s] in zone[uuid:%s], please at least create a default virtual router offering in that zone", l3Nw.getUuid(), l3Nw.getZoneUuid()); logger.warn(err.getDetails()); completion.fail(err); return; } if (struct.getVirtualRouterOfferingSelector() == null) { struct.setVirtualRouterOfferingSelector(new VirtualRouterOfferingSelector() { @Override public VirtualRouterOfferingInventory selectVirtualRouterOffering(L3NetworkInventory l3, List<VirtualRouterOfferingInventory> candidates) { Optional<VirtualRouterOfferingInventory> opt = candidates.stream().filter(VirtualRouterOfferingInventory::isDefault).findAny(); return !opt.isPresent() ? candidates.get(0) : opt.get(); } }); } VirtualRouterOfferingInventory offering = struct.getVirtualRouterOfferingSelector().selectVirtualRouterOffering(l3Nw, offerings); if (validator != null) { validator.validate(offering); } CreateVirtualRouterVmMsg msg = new CreateVirtualRouterVmMsg(); msg.setNotGatewayForGuestL3Network(struct.isNotGatewayForGuestL3Network()); msg.setL3Network(l3Nw); msg.setOffering(offering); msg.setInherentSystemTags(struct.getInherentSystemTags()); msg.setProviderType(struct.getProviderType()); msg.setApplianceVmType(struct.getApplianceVmType()); msg.setApplianceVmAgentPort(struct.getApplianceVmAgentPort()); createSubTaskProgress("create a virtual router vm"); bus.makeTargetServiceIdByResourceUuid(msg, VirtualRouterConstant.SERVICE_ID, l3Nw.getUuid()); bus.send(msg, new CloudBusCallBack(completion) { @Override public void run(MessageReply reply) { if (!reply.isSuccess()) { completion.fail(reply.getError()); } else { completion.success(((CreateVirtualRouterVmReply) reply).getInventory()); } } }); } @Override public void acquireVirtualRouterVm(VirtualRouterStruct struct, final ReturnValueCompletion<VirtualRouterVmInventory> completion) { for (BeforeAcquireVirtualRouterVmExtensionPoint extp : pluginRgty.getExtensionList( BeforeAcquireVirtualRouterVmExtensionPoint.class)) { extp.beforeAcquireVirtualRouterVmExtensionPoint(struct); } //TODO: find a way to remove the GLock String syncName = String.format("glock-vr-l3-%s", struct.getL3Network().getUuid()); thdf.chainSubmit(new ChainTask(completion) { @Override public String getSyncSignature() { return syncName; } @Override public void run(final SyncTaskChain chain) { final GLock lock = new GLock(syncName, TimeUnit.HOURS.toSeconds(1)); lock.setAlsoUseMemoryLock(false); lock.lock(); acquireVirtualRouterVmInternal(struct, new ReturnValueCompletion<VirtualRouterVmInventory>(chain, completion) { @Override public void success(VirtualRouterVmInventory returnValue) { lock.unlock(); completion.success(returnValue); chain.next(); } @Override public void fail(ErrorCode errorCode) { lock.unlock(); completion.fail(errorCode); chain.next(); } }); } @Override public String getName() { return syncName; } }); } @Override @Transactional(readOnly = true) public VirtualRouterVmInventory getVirtualRouterVm(L3NetworkInventory l3Nw) { String sql = "select vm from VirtualRouterVmVO vm, VmNicVO nic where vm.uuid = nic.vmInstanceUuid and nic.l3NetworkUuid = :l3Uuid and nic.metaData in (:guestMeta)"; TypedQuery<VirtualRouterVmVO> q = dbf.getEntityManager().createQuery(sql, VirtualRouterVmVO.class); q.setParameter("l3Uuid", l3Nw.getUuid()); q.setParameter("guestMeta", VirtualRouterNicMetaData.GUEST_NIC_MASK_STRING_LIST); List<VirtualRouterVmVO> vos = q.getResultList(); if (vos.isEmpty()) { return null; } for (VirtualRouterVmVO vo : vos) { if (ApplianceVmHaStatus.Master == vo.getHaStatus()) { return VirtualRouterVmInventory.valueOf(vo); } } return VirtualRouterVmInventory.valueOf(vos.get(0)); } @Override public boolean isVirtualRouterRunningForL3Network(String l3Uuid) { return countVirtualRouterRunningForL3Network(l3Uuid) > 0; } @Override @Transactional(readOnly = true) public long countVirtualRouterRunningForL3Network(String l3Uuid) { String sql = "select count(vm) from ApplianceVmVO vm, VmNicVO nic where vm.uuid = nic.vmInstanceUuid and vm.state = :vmState and nic.l3NetworkUuid = :l3Uuid and nic.metaData in (:guestMeta)"; TypedQuery<Long> q = dbf.getEntityManager().createQuery(sql, Long.class); q.setParameter("l3Uuid", l3Uuid); q.setParameter("vmState", VmInstanceState.Running); q.setParameter("guestMeta", VirtualRouterNicMetaData.GUEST_NIC_MASK_STRING_LIST); return q.getSingleResult(); } @Override @Transactional(readOnly = true) public boolean isVirtualRouterForL3Network(String l3Uuid) { String sql = "select vm from ApplianceVmVO vm, VmNicVO nic where vm.uuid = nic.vmInstanceUuid and nic.l3NetworkUuid = :l3Uuid and nic.metaData in (:guestMeta)"; TypedQuery<Long> q = dbf.getEntityManager().createQuery(sql, Long.class); q.setParameter("l3Uuid", l3Uuid); q.setParameter("guestMeta", VirtualRouterNicMetaData.GUEST_NIC_MASK_STRING_LIST); Long count = q.getSingleResult(); return count > 0; } @Transactional(readOnly = true) private List<VirtualRouterOfferingInventory> findOfferingByGuestL3Network(L3NetworkInventory guestL3) { String sql = "select offering from VirtualRouterOfferingVO offering, SystemTagVO stag where " + "offering.uuid = stag.resourceUuid and stag.resourceType = :type and offering.zoneUuid = :zoneUuid and stag.tag = :tag and offering.state = :state"; TypedQuery<VirtualRouterOfferingVO> q = dbf.getEntityManager().createQuery(sql, VirtualRouterOfferingVO.class); q.setParameter("type", InstanceOfferingVO.class.getSimpleName()); q.setParameter("zoneUuid", guestL3.getZoneUuid()); q.setParameter("tag", VirtualRouterSystemTags.VR_OFFERING_GUEST_NETWORK.instantiateTag(map(e(VirtualRouterSystemTags.VR_OFFERING_GUEST_NETWORK_TOKEN, guestL3.getUuid())))); q.setParameter("state", InstanceOfferingState.Enabled); List<VirtualRouterOfferingVO> vos = q.getResultList(); if (!vos.isEmpty()) { return VirtualRouterOfferingInventory.valueOf1(vos); } List<String> offeringUuids = VirtualRouterSystemTags.VIRTUAL_ROUTER_OFFERING.getTokensOfTagsByResourceUuid(guestL3.getUuid()) .stream().map(tokens -> tokens.get(VirtualRouterSystemTags.VIRTUAL_ROUTER_OFFERING_TOKEN)).collect(Collectors.toList()); if (!offeringUuids.isEmpty()) { return VirtualRouterOfferingInventory.valueOf1(Q.New(VirtualRouterOfferingVO.class) .in(VirtualRouterOfferingVO_.uuid, offeringUuids) .eq(VirtualRouterOfferingVO_.state, InstanceOfferingState.Enabled) .list()); } sql ="select offering from VirtualRouterOfferingVO offering where offering.zoneUuid = :zoneUuid and offering.state = :state"; q = dbf.getEntityManager().createQuery(sql, VirtualRouterOfferingVO.class); q.setParameter("zoneUuid", guestL3.getZoneUuid()); q.setParameter("state", InstanceOfferingState.Enabled); vos = q.getResultList(); return vos.isEmpty() ? null : VirtualRouterOfferingInventory.valueOf1(vos); } @Override public List<Flow> getPostCreateFlows() { List<Flow> flows = new ArrayList<>(); flows.addAll(postCreateFlowsBuilder.getFlows()); flows.addAll(postCreateFlowExtensionPoints.stream().map(VirtualRouterPostCreateFlowExtensionPoint::virtualRouterPostCreateFlow).collect(Collectors.toList())); return flows; } @Override public List<Flow> getPostStartFlows() { List<Flow> flows = new ArrayList<>(); flows.addAll(postStartFlowsBuilder.getFlows()); flows.addAll(postStartFlowExtensionPoints.stream().map(VirtualRouterPostStartFlowExtensionPoint::virtualRouterPostStartFlow).collect(Collectors.toList())); return flows; } @Override public List<Flow> getPostRebootFlows() { List<Flow> flows = new ArrayList<>(); flows.addAll(postRebootFlowsBuilder.getFlows()); flows.addAll(postRebootFlowExtensionPoints.stream().map(VirtualRouterPostRebootFlowExtensionPoint::virtualRouterPostRebootFlow).collect(Collectors.toList())); return flows; } @Override public List<Flow> getPostStopFlows() { return null; } @Override public List<Flow> getPostMigrateFlows() { return null; } @Override public List<Flow> getPostDestroyFlows() { List<Flow> flows = new ArrayList<>(); flows.addAll(postDestroyFlowsBuilder.getFlows()); flows.addAll(postDestroyFlowExtensionPoints.stream().map(VirtualRouterPostDestroyFlowExtensionPoint::virtualRouterPostDestroyFlow).collect(Collectors.toList())); return flows; } @Override public FlowChain getReconnectFlowChain() { FlowChain chain = reconnectFlowsBuilder.build(); for (VirtualRouterPostReconnectFlowExtensionPoint ext : postReconnectFlowExtensionPoints) { chain.then(ext.virtualRouterPostReconnectFlow()); } return chain; } @Override public int getParallelismDegree(String vrUuid) { Integer degree = vrParallelismDegrees.get(vrUuid); return degree == null ? VirtualRouterGlobalConfig.COMMANDS_PARALELLISM_DEGREE.value(Integer.class) : degree; } public void setVirtualRouterPostStartFlows(List<String> virtualRouterPostStartFlows) { this.virtualRouterPostStartFlows = virtualRouterPostStartFlows; } public void setVirtualRouterPostRebootFlows(List<String> virtualRouterPostRebootFlows) { this.virtualRouterPostRebootFlows = virtualRouterPostRebootFlows; } public void setVirtualRouterPostDestroyFlows(List<String> virtualRouterPostDestroyFlows) { this.virtualRouterPostDestroyFlows = virtualRouterPostDestroyFlows; } public void setVirtualRouterPostCreateFlows(List<String> virtualRouterPostCreateFlows) { this.virtualRouterPostCreateFlows = virtualRouterPostCreateFlows; } public void setVirtualRouterReconnectFlows(List<String> virtualRouterReconnectFlows) { this.virtualRouterReconnectFlows = virtualRouterReconnectFlows; } @Override public List<Class> getMessageClassToIntercept() { List<Class> classes = new ArrayList<Class>(); classes.add(APIAttachNetworkServiceToL3NetworkMsg.class); return classes; } @Override public InterceptorPosition getPosition() { return InterceptorPosition.END; } @Override public APIMessage intercept(APIMessage msg) throws ApiMessageInterceptionException { if (msg instanceof APIAttachNetworkServiceToL3NetworkMsg) { validate((APIAttachNetworkServiceToL3NetworkMsg) msg); } return msg; } private void validate(APIAttachNetworkServiceToL3NetworkMsg msg) { List<String> services = msg.getNetworkServices().get(virtualRouterProvider.getUuid()); if (services == null) { return; } boolean snat = false; boolean portForwarding = false; boolean eip = false; SimpleQuery<NetworkServiceL3NetworkRefVO> q = dbf.createQuery(NetworkServiceL3NetworkRefVO.class); q.add(NetworkServiceL3NetworkRefVO_.l3NetworkUuid, Op.EQ, msg.getL3NetworkUuid()); List<NetworkServiceL3NetworkRefVO> refs = q.list(); for (NetworkServiceL3NetworkRefVO ref : refs) { if (ref.getNetworkServiceType().equals(NetworkServiceType.SNAT.toString())) { snat = true; } } for (String s : services) { if (NetworkServiceType.PortForwarding.toString().equals(s)) { portForwarding = true; } if (NetworkServiceType.SNAT.toString().equals(s)) { snat = true; } if (EipConstant.EIP_NETWORK_SERVICE_TYPE.equals(s)) { eip = true; } } if (!snat && eip) { throw new ApiMessageInterceptionException(argerr("failed tot attach virtual router network services to l3Network[uuid:%s]. When eip is selected, snat must be selected too", msg.getL3NetworkUuid())); } if (!snat && portForwarding) { throw new ApiMessageInterceptionException(argerr("failed tot attach virtual router network services to l3Network[uuid:%s]. When port forwarding is selected, snat must be selected too", msg.getL3NetworkUuid())); } } @Override public List<ExpandedQueryStruct> getExpandedQueryStructs() { List<ExpandedQueryStruct> structs = new ArrayList<ExpandedQueryStruct>(); ExpandedQueryStruct struct = new ExpandedQueryStruct(); struct.setExpandedField("virtualRouterEipRef"); struct.setExpandedInventoryKey("virtualRouterVmUuid"); struct.setHidden(true); struct.setForeignKey("uuid"); struct.setInventoryClass(VirtualRouterEipRefInventory.class); struct.setInventoryClassToExpand(ApplianceVmInventory.class); structs.add(struct); struct = new ExpandedQueryStruct(); struct.setExpandedField("virtualRouterVipRef"); struct.setExpandedInventoryKey("virtualRouterVmUuid"); struct.setHidden(true); struct.setForeignKey("uuid"); struct.setInventoryClass(VirtualRouterVipInventory.class); struct.setInventoryClassToExpand(ApplianceVmInventory.class); structs.add(struct); struct = new ExpandedQueryStruct(); struct.setExpandedField("virtualRouterPortforwardingRef"); struct.setExpandedInventoryKey("virtualRouterVmUuid"); struct.setHidden(true); struct.setForeignKey("uuid"); struct.setInventoryClass(VirtualRouterPortForwardingRuleRefInventory.class); struct.setInventoryClassToExpand(ApplianceVmInventory.class); structs.add(struct); struct = new ExpandedQueryStruct(); struct.setExpandedField("virtualRouterOffering"); struct.setExpandedInventoryKey("uuid"); struct.setForeignKey("instanceOfferingUuid"); struct.setInventoryClass(VirtualRouterOfferingInventory.class); struct.setInventoryClassToExpand(ApplianceVmInventory.class); struct.setSuppressedInventoryClass(InstanceOfferingInventory.class); structs.add(struct); return structs; } @Override public List<ExpandedQueryAliasStruct> getExpandedQueryAliasesStructs() { List<ExpandedQueryAliasStruct> aliases = new ArrayList<ExpandedQueryAliasStruct>(); ExpandedQueryAliasStruct as = new ExpandedQueryAliasStruct(); as.setInventoryClass(ApplianceVmInventory.class); as.setAlias("eip"); as.setExpandedField("virtualRouterEipRef.eip"); aliases.add(as); as = new ExpandedQueryAliasStruct(); as.setInventoryClass(ApplianceVmInventory.class); as.setAlias("vip"); as.setExpandedField("virtualRouterVipRef.vip"); aliases.add(as); as = new ExpandedQueryAliasStruct(); as.setInventoryClass(ApplianceVmInventory.class); as.setAlias("portForwarding"); as.setExpandedField("virtualRouterPortforwardingRef.portForwarding"); aliases.add(as); return aliases; } @Override @Transactional(readOnly = true) public List<VmNicInventory> filterVmNicsForEipInVirtualRouter(VipInventory vip, List<VmNicInventory> candidates) { if (candidates.isEmpty()){ return candidates; } // Note(WeiW) Check vip has attached virtual router network Boolean vipForVirtualRouter = null; if (vip.getPeerL3NetworkUuids() != null && !vip.getPeerL3NetworkUuids().isEmpty()) { // Note(WeiW): The peer l3 must be all of vrouter l3 or flat l3 NetworkServiceProviderType providerType = nwServiceMgr. getTypeOfNetworkServiceProviderForService(vip.getPeerL3NetworkUuids().get(0), EipConstant.EIP_TYPE); // Todo(WeiW): Need to refactor to avoid hard code if (providerType.toString().equals(VYOS_ROUTER_PROVIDER_TYPE) || providerType.toString().equals(VIRTUAL_ROUTER_PROVIDER_TYPE)) { vipForVirtualRouter = true; } else { vipForVirtualRouter = false; } } // 1.get the vm nics which are managed by vrouter or virtual router. // it also means to ignore vm in flat. List<String> privateL3Uuids = candidates.stream().map(VmNicInventory::getL3NetworkUuid).distinct() .collect(Collectors.toList()); /*innerL3: vRouter:Eip network service*/ List<String> innerl3Uuids = SQL.New("select distinct ref.l3NetworkUuid" + " from NetworkServiceL3NetworkRefVO ref, NetworkServiceProviderVO pro" + " where pro.type in (:providerTypes)" + " and ref.networkServiceProviderUuid = pro.uuid" + " and ref.networkServiceType = :serviceType" + " and ref.l3NetworkUuid in (:l3Uuids)", String.class) .param("l3Uuids", privateL3Uuids) .param("serviceType", EipConstant.EIP_NETWORK_SERVICE_TYPE) .param("providerTypes", Arrays.asList( VyosConstants.PROVIDER_TYPE.toString(), VirtualRouterConstant.PROVIDER_TYPE.toString())) .list(); List<VmNicInventory> vmNicInVirtualRouter = candidates.stream().filter(nic -> innerl3Uuids.contains(nic.getL3NetworkUuid())) .collect(Collectors.toList()); if (vipForVirtualRouter != null && vipForVirtualRouter == true) { List<String> vrUuids = vipProxy.getVrUuidsByNetworkService(VipVO.class.getSimpleName(), vip.getUuid()); String vrUuid; if (vrUuids == null || vrUuids.isEmpty()) { vrUuid = getVipPeerL3NetworkAttachedVirtualRouter(vip); } else { vrUuid = vrUuids.get(0); } if (vrUuid != null) { List<String> vrAttachedGuestL3 = Q.New(VmNicVO.class).select(VmNicVO_.l3NetworkUuid).eq(VmNicVO_.vmInstanceUuid, vrUuid).eq(VmNicVO_.metaData, GUEST_NIC_MASK).listValues(); logger.debug(String.format("there is virtual router[uuid:%s] associate with vip[uuid:%s], will return candidates from vr guest l3 networks[%s]", vrUuid, vip.getUuid(), vrAttachedGuestL3)); Set<VmNicInventory> r = candidates.stream() .filter(nic -> vrAttachedGuestL3.contains(nic.getL3NetworkUuid())) .collect(Collectors.toSet()); return new ArrayList<>(r); } logger.debug(String.format("there are no virtual router associate with vip[uuid:%s], and peer l3 exists, will return candidates from peer l3 networks[%s]", vip.getUuid(), vip.getPeerL3NetworkUuids())); Set<VmNicInventory> r = candidates.stream() .filter(nic -> vip.getPeerL3NetworkUuids().contains(nic.getL3NetworkUuid())) .collect(Collectors.toSet()); return new ArrayList<>(r); } else if (vipForVirtualRouter != null && vipForVirtualRouter == false) { logger.debug(String.format("remove all vmnics in virtual router network since vip[uuid:%s] has used in network which is not %s or %s", vip.getUuid(), VYOS_ROUTER_PROVIDER_TYPE, VIRTUAL_ROUTER_PROVIDER_TYPE)); candidates.removeAll(vmNicInVirtualRouter); return candidates; } // 2. keep vmnics which associated vrouter attached public network of vip if (!innerl3Uuids.isEmpty()) { List<String> peerL3Uuids = SQL.New("select l3.uuid" + " from VmNicVO nic, L3NetworkVO l3" + " where nic.vmInstanceUuid in " + " (" + " select vm.uuid" + " from VmNicVO nic, ApplianceVmVO vm" + " where nic.l3NetworkUuid = :l3NetworkUuid" + " and nic.vmInstanceUuid = vm.uuid" + " )" + " and l3.uuid = nic.l3NetworkUuid" + " and l3.uuid in (:virtualNetworks)" + " and l3.system = :isSystem") .param("l3NetworkUuid", vip.getL3NetworkUuid()) .param("virtualNetworks", innerl3Uuids) .param("isSystem", false) .list(); Set<VmNicInventory> r = candidates.stream() .filter(nic -> peerL3Uuids.contains(nic.getL3NetworkUuid())) .collect(Collectors.toSet()); candidates.removeAll(vmNicInVirtualRouter); candidates.addAll(r); } else { candidates.removeAll(vmNicInVirtualRouter); } return candidates; } private String getVipPeerL3NetworkAttachedVirtualRouter(VipInventory vip) { for (String l3Uuid : vip.getPeerL3NetworkUuids()) { List<String> vrUuids = Q.New(VmNicVO.class).select(VmNicVO_.vmInstanceUuid).eq(VmNicVO_.l3NetworkUuid, l3Uuid).eq(VmNicVO_.metaData, GUEST_NIC_MASK).listValues(); if (vrUuids == null || vrUuids.isEmpty()) { return null; } vrUuids = Q.New(ApplianceVmVO.class).select(ApplianceVmVO_.uuid).in(ApplianceVmVO_.uuid, vrUuids) .notEq(ApplianceVmVO_.haStatus, ApplianceVmHaStatus.Backup).listValues(); if (vrUuids == null || vrUuids.isEmpty()) { return null; } return vrUuids.get(0); } return null; } private String getDedicatedRoleVrUuidFromVrUuids(List<String> uuids, String loadBalancerUuid) { Set<String> vrUuids = new HashSet<>(uuids); if (vrUuids.size() == 2 && LoadBalancerSystemTags.SEPARATE_VR.hasTag(loadBalancerUuid) && vrUuids.stream().anyMatch(uuid -> VirtualRouterSystemTags.DEDICATED_ROLE_VR.hasTag(uuid))) { for (String uuid : vrUuids) { if (VirtualRouterSystemTags.DEDICATED_ROLE_VR.hasTag(uuid)) { return uuid; } } } if (vrUuids.size() == 1) { return vrUuids.iterator().next(); } else if (vrUuids.size() == 0) { return null; } else { throw new CloudRuntimeException(String.format("there are multiple virtual routers[uuids:%s]", vrUuids)); } } private String getVirtualRouterVmAttachedLoadBalancer(String lbUuid) { List<String> vrUuids = lbProxy.getVrUuidsByNetworkService(LoadBalancerVO.class.getSimpleName(), lbUuid); String vrUuid = getDedicatedRoleVrUuidFromVrUuids(vrUuids, lbUuid); if (vrUuid != null) { return vrUuid; } final List<String> peerL3NetworkUuids = SQL.New("select peer.l3NetworkUuid " + "from LoadBalancerVO lb, VipVO vip, VipPeerL3NetworkRefVO peer " + "where lb.vipUuid = vip.uuid " + "and vip.uuid = peer.vipUuid " + "and lb.uuid = :lbUuid").param("lbUuid", lbUuid).list(); if (peerL3NetworkUuids != null && !peerL3NetworkUuids.isEmpty()) { vrUuids = Q.New(VmNicVO.class).select(VmNicVO_.vmInstanceUuid) .in(VmNicVO_.l3NetworkUuid, peerL3NetworkUuids) .eq(VmNicVO_.metaData, VirtualRouterNicMetaData.GUEST_NIC_MASK) .listValues(); if (vrUuids != null && !vrUuids.isEmpty()) { /* filter backup router */ vrUuids = Q.New(ApplianceVmVO.class).select(ApplianceVmVO_.uuid).in(ApplianceVmVO_.uuid, vrUuids) .notEq(ApplianceVmVO_.haStatus, ApplianceVmHaStatus.Backup).listValues(); } vrUuid = getDedicatedRoleVrUuidFromVrUuids(vrUuids, lbUuid); if (vrUuid != null) { return vrUuid; } } VipVO lbVipVO = SQL.New("select vip from LoadBalancerVO lb, VipVO vip " + "where lb.vipUuid = vip.uuid " + "and lb.uuid = :lbUuid") .param("lbUuid", lbUuid).find(); if (lbVipVO != null) { List<String> useFor = Q.New(VipNetworkServicesRefVO.class).select(VipNetworkServicesRefVO_.serviceType).eq(VipNetworkServicesRefVO_.vipUuid, lbVipVO.getUuid()).listValues(); if(useFor != null && useFor.contains(SNAT_NETWORK_SERVICE_TYPE)) { vrUuids = vipProxy.getVrUuidsByNetworkService(VipVO.class.getSimpleName(), lbVipVO.getUuid()); return vrUuids.get(0); } } return null; } @Override public List<L3NetworkInventory> getPeerL3NetworksForLoadBalancer(String lbUuid, List<L3NetworkInventory> candidates) { if(candidates == null || candidates.isEmpty()){ return candidates; } /*get vr*/ String vrUuid = getVirtualRouterVmAttachedLoadBalancer(lbUuid); if (vrUuid != null) { return new SQLBatchWithReturn<List<L3NetworkInventory>>(){ @Override protected List<L3NetworkInventory> scripts() { List<String> guestL3Uuids = Q.New(VmNicVO.class) .select(VmNicVO_.l3NetworkUuid) .eq(VmNicVO_.vmInstanceUuid, vrUuid) .eq(VmNicVO_.metaData, VirtualRouterNicMetaData.GUEST_NIC_MASK) .listValues(); if (guestL3Uuids == null || guestL3Uuids.isEmpty()) { return new ArrayList<>(); } return candidates.stream().filter(l3 -> guestL3Uuids.contains(l3.getUuid())).collect(Collectors.toList()); } }.execute(); } /*get peer network of vip, vr has been deleted, so just return these peer networks*/ final List<String> peerL3NetworkUuids = SQL.New("select peer.l3NetworkUuid " + "from LoadBalancerVO lb, VipVO vip, VipPeerL3NetworkRefVO peer " + "where lb.vipUuid = vip.uuid " + "and vip.uuid = peer.vipUuid " + "and lb.uuid = :lbUuid").param("lbUuid", lbUuid).list(); if (peerL3NetworkUuids != null && !peerL3NetworkUuids.isEmpty()) { return candidates.stream().filter(n -> peerL3NetworkUuids.contains(n.getUuid())) .collect(Collectors.toList()); } return new SQLBatchWithReturn<List<L3NetworkInventory>>(){ @Override protected List<L3NetworkInventory> scripts() { //1.get the l3 which are managed by vrouter or virtual router. List<String> inners = sql("select distinct l3.uuid from L3NetworkVO l3, NetworkServiceL3NetworkRefVO ref, NetworkServiceProviderVO pro" + " where l3.uuid = ref.l3NetworkUuid and ref.networkServiceProviderUuid = pro.uuid and l3.uuid in (:l3Uuids)" + " and pro.type in (:providerType)", String.class) .param("l3Uuids", candidates.stream().map(L3NetworkInventory::getUuid).collect(Collectors.toList())) .param("providerType", Arrays.asList(VyosConstants.PROVIDER_TYPE.toString(),VirtualRouterConstant.PROVIDER_TYPE.toString())) .list(); List<L3NetworkInventory> ret = candidates.stream().filter(l3 -> inners.contains(l3.getUuid())).collect(Collectors.toList()); if(ret.size() == 0){ return new ArrayList<>(); } VipVO lbVipVO = SQL.New("select vip from LoadBalancerVO lb, VipVO vip " + "where lb.vipUuid = vip.uuid " + "and lb.uuid = :lbUuid") .param("lbUuid", lbUuid).find(); //2.check the l3 is peer l3 of the loadbalancer L3NetworkVO vipNetwork = Q.New(L3NetworkVO.class).eq(L3NetworkVO_.uuid, lbVipVO.getL3NetworkUuid()).find(); List<String> peerL3Uuids = SQL.New("select l3.uuid" + " from VmNicVO nic, L3NetworkVO l3" + " where nic.vmInstanceUuid in " + " (" + " select vm.uuid" + " from VmNicVO nic, ApplianceVmVO vm" + " where nic.l3NetworkUuid = :l3NetworkUuid" + " and nic.vmInstanceUuid = vm.uuid" + " )"+ " and l3.uuid = nic.l3NetworkUuid" + " and nic.metaData = :metaData" + " and l3.system = :isSystem") .param("l3NetworkUuid", vipNetwork.getUuid()) .param("isSystem", false) .param("metaData", VirtualRouterNicMetaData.GUEST_NIC_MASK.toString()) .list(); // 3. filter all the l3 networks which are not managed by vrouter or virtual router currently and // have been attached the virtualrouter offers, // such as without other services except for vrouter lb services List<String> excludeL3Uuids = SQL.New("select l3.uuid" + " from VmNicVO nic, L3NetworkVO l3" + " where l3.uuid in (:l3NetworkUuids)" + " and l3.uuid = nic.l3NetworkUuid" + " and nic.metaData = :metaData" + " and l3.system = :isSystem") .param("l3NetworkUuids", inners) .param("isSystem", false) .param("metaData", VirtualRouterNicMetaData.GUEST_NIC_MASK.toString()) .list(); inners.removeAll(excludeL3Uuids); peerL3Uuids.addAll(selectGuestL3NetworksNeedingSpecificNetworkService(inners, LoadBalancerConstants.LB_NETWORK_SERVICE_TYPE, vipNetwork.getUuid())); return ret.stream().filter(l3 -> peerL3Uuids.contains(l3.getUuid())).collect(Collectors.toList()); } }.execute(); } @Override public List<VmNicInventory> getCandidateVmNicsForLoadBalancerInVirtualRouter(APIGetCandidateVmNicsForLoadBalancerMsg msg, List<VmNicInventory> candidates) { if(candidates == null || candidates.isEmpty()){ return candidates; } String vrUuid = getVirtualRouterVmAttachedLoadBalancer( msg.getLoadBalancerUuid()); if (vrUuid != null) { return getCandidateVmNicsIfLoadBalancerBound(msg, candidates, vrUuid); } final List<String> peerL3NetworkUuids = SQL.New("select peer.l3NetworkUuid " + "from LoadBalancerVO lb, VipVO vip, VipPeerL3NetworkRefVO peer " + "where lb.vipUuid = vip.uuid " + "and vip.uuid = peer.vipUuid " + "and lb.uuid = :lbUuid") .param("lbUuid", msg.getLoadBalancerUuid()) .list(); if (peerL3NetworkUuids != null && !peerL3NetworkUuids.isEmpty()) { return getCandidateVmNicsIfPeerL3NetworkExists(msg, candidates, peerL3NetworkUuids); } return new SQLBatchWithReturn<List<VmNicInventory>>(){ @Override protected List<VmNicInventory> scripts() { VipVO lbVipVO = SQL.New("select vip from LoadBalancerVO lb, VipVO vip " + "where lb.vipUuid = vip.uuid " + "and lb.uuid = :lbUuid") .param("lbUuid", msg.getLoadBalancerUuid()).find(); //1.get the l3 networks which has the vrouter lb network service. List<String> inners = sql("select l3.uuid from L3NetworkVO l3, NetworkServiceL3NetworkRefVO ref, NetworkServiceProviderVO pro" + " where l3.uuid = ref.l3NetworkUuid and ref.networkServiceProviderUuid = pro.uuid and l3.uuid in (:l3Uuids)" + " and pro.type in (:providerType)", String.class) .param("l3Uuids", candidates.stream().map(VmNicInventory::getL3NetworkUuid).collect(Collectors.toList())) .param("providerType", Arrays.asList(VyosConstants.PROVIDER_TYPE.toString(),VirtualRouterConstant.PROVIDER_TYPE.toString())) .list(); List<VmNicInventory> ret = candidates.stream().filter(nic -> inners.contains(nic.getL3NetworkUuid())).collect(Collectors.toList()); if(ret.size() == 0){ return new ArrayList<VmNicInventory>(); } //2.check the l3 of vm nic is peer l3 of the loadbalancer L3NetworkVO vipNetwork = Q.New(L3NetworkVO.class).eq(L3NetworkVO_.uuid, lbVipVO.getL3NetworkUuid()).find(); List<String> peerL3Uuids = SQL.New("select l3.uuid" + " from VmNicVO nic, L3NetworkVO l3" + " where nic.vmInstanceUuid in " + " (" + " select vm.uuid" + " from VmNicVO nic, ApplianceVmVO vm" + " where nic.l3NetworkUuid = :l3NetworkUuid" + " and nic.vmInstanceUuid = vm.uuid" + " )"+ " and l3.uuid = nic.l3NetworkUuid" + " and nic.metaData = :metaData" + " and l3.system = :isSystem") .param("l3NetworkUuid", vipNetwork.getUuid()) .param("isSystem", false) .param("metaData", VirtualRouterNicMetaData.GUEST_NIC_MASK.toString()) .list(); // 3. filter all the l3 networks which are not managed by vrouter or virtual router currently and // have been attached the virtualrouter offers, // such as without other services except for vrouter lb services List<String> excludeL3Uuids = SQL.New("select l3.uuid" + " from VmNicVO nic, L3NetworkVO l3" + " where l3.uuid in (:l3NetworkUuids)" + " and l3.uuid = nic.l3NetworkUuid" + " and nic.metaData = :metaData" + " and l3.system = :isSystem") .param("l3NetworkUuids", inners) .param("isSystem", false) .param("metaData", VirtualRouterNicMetaData.GUEST_NIC_MASK.toString()) .list(); inners.removeAll(excludeL3Uuids); peerL3Uuids.addAll(selectGuestL3NetworksNeedingSpecificNetworkService(inners, LoadBalancerConstants.LB_NETWORK_SERVICE_TYPE, vipNetwork.getUuid())); return ret.stream().filter(nic -> peerL3Uuids.contains(nic.getL3NetworkUuid())).collect(Collectors.toList()); } }.execute(); } private List<VmNicInventory> getCandidateVmNicsIfPeerL3NetworkExists(APIGetCandidateVmNicsForLoadBalancerMsg msg, List<VmNicInventory> candidates, List<String> peerL3NetworkUuids) { List<String> attachedVmNicUuids = Q.New(LoadBalancerListenerVmNicRefVO.class) .select(LoadBalancerListenerVmNicRefVO_.vmNicUuid) .eq(LoadBalancerListenerVmNicRefVO_.listenerUuid, msg.getListenerUuid()) .listValues(); return candidates.stream() .filter(n -> peerL3NetworkUuids.contains(n.getL3NetworkUuid())) .filter(n -> !attachedVmNicUuids.contains(n.getUuid())) .collect(Collectors.toList()); } private List<VmNicInventory> getCandidateVmNicsIfLoadBalancerBound(APIGetCandidateVmNicsForLoadBalancerMsg msg, List<VmNicInventory> candidates, String vrUuid) { List<String> candidatesUuids = candidates.stream().map(n -> n.getUuid()).collect(Collectors.toList()); logger.debug(String.format("loadbalancer[uuid:%s] has bound to virtual router[uuid:%s], " + "continue working with vmnics:%s", msg.getLoadBalancerUuid(), vrUuid, candidatesUuids)); return new SQLBatchWithReturn<List<VmNicInventory>>(){ @Override protected List<VmNicInventory> scripts() { List<String> guestL3Uuids = Q.New(VmNicVO.class) .select(VmNicVO_.l3NetworkUuid) .eq(VmNicVO_.vmInstanceUuid, vrUuid) .eq(VmNicVO_.metaData, VirtualRouterNicMetaData.GUEST_NIC_MASK) .listValues(); if (guestL3Uuids == null || guestL3Uuids.isEmpty()) { return new ArrayList<>(); } List<String> vmNicUuids = SQL.New("select nic.uuid from VmNicVO nic, VmInstanceEO vm " + "where vm.uuid = nic.vmInstanceUuid " + "and vm.type = :vmType " + "and vm.state in (:vmState) " + "and nic.l3NetworkUuid in (:l3s) " + "and nic.metaData is NULL") .param("vmType", VmInstanceConstant.USER_VM_TYPE.toString()) .param("vmState", asList(VmInstanceState.Running, VmInstanceState.Stopped)) .param("l3s", guestL3Uuids) .list(); List<String> attachedVmNicUuids = Q.New(LoadBalancerListenerVmNicRefVO.class) .select(LoadBalancerListenerVmNicRefVO_.vmNicUuid) .eq(LoadBalancerListenerVmNicRefVO_.listenerUuid, msg.getListenerUuid()) .listValues(); return candidates.stream() .filter( nic -> vmNicUuids.contains(nic.getUuid())) .filter( nic -> !attachedVmNicUuids.contains(nic.getUuid())) .collect(Collectors.toList()); } }.execute(); } private void applianceVmsCascadeDeleteAdditionPubclicNic(List<VmNicInventory> toDeleteNics) { ErrorCodeList errList = new ErrorCodeList(); FutureCompletion completion = new FutureCompletion(null); new While<>(toDeleteNics).each((VmNicInventory nic, WhileCompletion completion1) -> { if (!dbf.isExist(nic.getUuid(), VmNicVO.class)) { logger.debug(String.format("nic[uuid:%s] not exists, skip", nic.getUuid())); completion1.done(); return; } DetachNicFromVmMsg msg = new DetachNicFromVmMsg(); msg.setVmNicUuid(nic.getUuid()); msg.setVmInstanceUuid(nic.getVmInstanceUuid()); bus.makeTargetServiceIdByResourceUuid(msg, VmInstanceConstant.SERVICE_ID, nic.getVmInstanceUuid()); bus.send(msg, new CloudBusCallBack(null) { @Override public void run(MessageReply reply) { if (!reply.isSuccess()) { if (!dbf.isExist(nic.getUuid(), VmNicVO.class)) { logger.info(String.format("nic[uuid:%s] not exists, mark it as success", nic.getUuid())); completion1.done(); } else { errList.getCauses().add(reply.getError()); logger.error(String.format("detach nic[uuid: %s] for " + "delete l3[uuid: %s] failed", nic.getUuid(), nic.getL3NetworkUuid())); completion1.allDone(); } } else { logger.debug(String.format("detach nic[uuid: %s] for " + "delete l3[uuid: %s] success", nic.getUuid(), nic.getL3NetworkUuid())); completion1.done(); } } }); }).run(new NoErrorCompletion() { @Override public void done() { if (!errList.getCauses().isEmpty()) { completion.fail(errList.getCauses().get(0)); } else { logger.info(String.format("detach nics[%s] for delete l3[uuid:%s] success", toDeleteNics.stream() .map(n -> n.getUuid()) .collect(Collectors.toList()), toDeleteNics.stream().map(n-> n.getL3NetworkUuid()).collect(Collectors.toSet()))); completion.success(); } } }); completion.await(TimeUnit.MINUTES.toMillis(30)); if (!completion.isSuccess()) { throw new OperationFailureException(operr("can not detach nic [uuid:%s]", toDeleteNics.stream() .map(n -> n.getUuid()) .collect(Collectors.toList())).causedBy(completion.getErrorCode())); } } private List<ApplianceVmVO> applianceVmsToBeDeleted(List<ApplianceVmVO> applianceVmVOS, List<String> deletedUuids) { List<ApplianceVmVO> vos = new ArrayList<>(); for (ApplianceVmVO vo : applianceVmVOS) { VirtualRouterVmInventory vrInv = VirtualRouterVmInventory.valueOf(dbf.findByUuid(vo.getUuid(), VirtualRouterVmVO.class)); List<String> l3Uuids = new ArrayList<>(); l3Uuids.addAll(vrInv.getGuestL3Networks()); l3Uuids.add(vrInv.getPublicNetworkUuid()); l3Uuids.add(vrInv.getManagementNetworkUuid()); l3Uuids.add(vrInv.getDefaultRouteL3NetworkUuid()); for(String uuid: l3Uuids) { if (deletedUuids.contains(uuid)) { vos.add(vo); break; } } } return vos; } List<VmNicInventory> applianceVmsAdditionalPublicNic(List<ApplianceVmVO> applianceVmVOS, List<String> parentIssuerUuids) { List<VmNicInventory> toDeleteNics = new ArrayList<>(); for (ApplianceVmVO vo : applianceVmVOS) { VirtualRouterVmInventory vrInv = VirtualRouterVmInventory.valueOf(dbf.findByUuid(vo.getUuid(), VirtualRouterVmVO.class)); for (VmNicInventory nic : vrInv.getAdditionalPublicNics()) { /* skip default router nic */ if (nic.getL3NetworkUuid().equals(vrInv.getDefaultRouteL3NetworkUuid())) { continue; } if (parentIssuerUuids.contains(nic.getL3NetworkUuid())) { toDeleteNics.add(nic); } } } return toDeleteNics; } @Override public List<ApplianceVmVO> filterApplianceVmCascade(List<ApplianceVmVO> applianceVmVOS, String parentIssuer, List<String> parentIssuerUuids) { if (parentIssuer.equals(L3NetworkVO.class.getSimpleName())) { List<ApplianceVmVO> vos = applianceVmsToBeDeleted(applianceVmVOS, parentIssuerUuids); applianceVmVOS.removeAll(vos); List<VmNicInventory> toDeleteNics = applianceVmsAdditionalPublicNic(applianceVmVOS, parentIssuerUuids); applianceVmsCascadeDeleteAdditionPubclicNic(toDeleteNics); return vos; } else if (parentIssuer.equals(IpRangeVO.class.getSimpleName())) { final List<String> iprL3Uuids = CollectionUtils.transformToList((List<String>) parentIssuerUuids, new Function<String, String>() { @Override public String call(String arg) { return Q.New(NormalIpRangeVO.class).eq(NormalIpRangeVO_.uuid, arg).select(NormalIpRangeVO_.l3NetworkUuid).findValue(); } }); List<ApplianceVmVO> vos = applianceVmsToBeDeleted(applianceVmVOS, iprL3Uuids); applianceVmVOS.removeAll(vos); List<VmNicInventory> toDeleteNics = applianceVmsAdditionalPublicNic(applianceVmVOS, iprL3Uuids); applianceVmsCascadeDeleteAdditionPubclicNic(toDeleteNics); return vos; } else { return applianceVmVOS; } } private void reconenctVirtualRouter(String vrUUid) { ReconnectVirtualRouterVmMsg msg = new ReconnectVirtualRouterVmMsg(); msg.setVirtualRouterVmUuid(vrUUid); bus.makeTargetServiceIdByResourceUuid(msg, VmInstanceConstant.SERVICE_ID, vrUUid); bus.send(msg, new CloudBusCallBack(msg) { @Override public void run(MessageReply reply) { if (!reply.isSuccess()) { logger.warn(String.format("virtual router[uuid:%s] reconnection failed, because %s", vrUUid, reply.getError())); } else { logger.debug(String.format("virtual router[uuid:%s] reconnect successfully", vrUUid)); } } }); } private void handle(CheckVirtualRouterVmVersionMsg cmsg) { CheckVirtualRouterVmVersionReply reply = new CheckVirtualRouterVmVersionReply(); /* reply message back asap to avoid blocking mn node startup */ bus.reply(cmsg, reply); VirtualRouterVmVO vrVo = dbf.findByUuid(cmsg.getVirtualRouterVmUuid(), VirtualRouterVmVO.class); VirtualRouterVmInventory inv = VirtualRouterVmInventory.valueOf(vrVo); if (VirtualRouterConstant.VIRTUAL_ROUTER_VM_TYPE.equals(inv.getApplianceVmType())) { return; } if (vrVo.getStatus() == ApplianceVmStatus.Connecting) { reconenctVirtualRouter(inv.getUuid()); return; } if (vrVo.getHaStatus() == ApplianceVmHaStatus.Backup) { reconenctVirtualRouter(inv.getUuid()); return; } vyosVersionManager.vyosRouterVersionCheck(inv.getUuid(), new ReturnValueCompletion<VyosVersionCheckResult>(cmsg) { @Override public void success(VyosVersionCheckResult returnValue) { if (returnValue.isNeedReconnect()) { logger.warn(String.format("virtual router[uuid: %s] need to be reconnected", inv.getUuid())); reconenctVirtualRouter(inv.getUuid()); } } @Override public void fail(ErrorCode errorCode) { } }); } @Override public void managementNodeReady() { List<VirtualRouterVmVO> vrVos = Q.New(VirtualRouterVmVO.class).list(); for (VirtualRouterVmVO vrVo : vrVos) { CheckVirtualRouterVmVersionMsg msg = new CheckVirtualRouterVmVersionMsg(); msg.setVirtualRouterVmUuid(vrVo.getUuid()); bus.makeTargetServiceIdByResourceUuid(msg, VirtualRouterConstant.SERVICE_ID, vrVo.getUuid()); bus.send(msg, new CloudBusCallBack(msg) { @Override public void run(MessageReply reply) { if (!reply.isSuccess()) { logger.warn(String.format("virtual router[uuid:%s] check version message failed, because %s", vrVo.getUuid(), reply.getError())); } else { logger.debug(String.format("virtual router[uuid:%s] check version message successfully", vrVo.getUuid())); } } }); } } @Override public void cleanupVip(String uuid) { SQL.New(VirtualRouterVipVO.class).eq(VirtualRouterVipVO_.uuid, uuid).delete(); } @Override public List<String> getL3NetworkForEipInVirtualRouter(String networkServiceProviderType, VipInventory vip) { if (networkServiceProviderType.equals(VYOS_ROUTER_PROVIDER_TYPE)) { L3NetworkVO l3Vo = Q.New(L3NetworkVO.class).eq(L3NetworkVO_.uuid, vip.getL3NetworkUuid()).find(); /* get vpc network or vrouter network */ return SQL.New("select distinct l3.uuid" + " from L3NetworkVO l3, NetworkServiceL3NetworkRefVO ref, NetworkServiceProviderVO provider" + " where l3.uuid = ref.l3NetworkUuid and ref.networkServiceProviderUuid = provider.uuid" + " and provider.type = :providerType" + " and l3.ipVersion = :ipVersion") .param("providerType", VYOS_ROUTER_PROVIDER_TYPE) .param("ipVersion", l3Vo.getIpVersion()) .list(); } return new ArrayList<>(); } public VmNicInventory getSnatPubicInventory(VirtualRouterVmInventory vrInv) { VmNicInventory publicNic = new VmNicInventory(); for (VmNicInventory vnic : vrInv.getVmNics()) { if (VmNicHelper.getL3Uuids(vnic).contains(vrInv.getDefaultRouteL3NetworkUuid())) { publicNic.setDeviceId(vnic.getDeviceId()); publicNic.setGateway(vnic.getGateway()); publicNic.setHypervisorType(vnic.getHypervisorType()); publicNic.setInternalName(vnic.getInternalName()); publicNic.setIp(vnic.getIp()); publicNic.setIpVersion(vnic.getIpVersion()); publicNic.setL3NetworkUuid(vnic.getL3NetworkUuid()); publicNic.setMac(vnic.getMac()); publicNic.setMetaData(vnic.getMetaData()); publicNic.setNetmask(vnic.getNetmask()); publicNic.setUuid(vnic.getUuid()); publicNic.setVmInstanceUuid(vnic.getVmInstanceUuid()); } } String publicIp = null; for (VirtualRouterHaGroupExtensionPoint ext : pluginRgty.getExtensionList(VirtualRouterHaGroupExtensionPoint.class)) { publicIp = ext.getPublicIp(vrInv.getUuid(), vrInv.getDefaultRouteL3NetworkUuid()); } if (publicIp != null) { publicNic.setIp(publicIp); } return publicNic; } private List<VirtualRouterCommands.SNATInfo> getSnatInfo(VirtualRouterVmInventory vrInv) { boolean snatDisable = haBackend.isSnatDisabledOnRouter(vrInv.getUuid()); if (snatDisable) { return null; } List<String> nwServed = vrInv.getAllL3Networks(); nwServed = selectL3NetworksNeedingSpecificNetworkService(nwServed, NetworkServiceType.SNAT); if (nwServed.isEmpty()) { return null; } VmNicInventory publicNic = getSnatPubicInventory(vrInv); final List<VirtualRouterCommands.SNATInfo> snatInfo = new ArrayList<>(); for (VmNicInventory vnic : vrInv.getVmNics()) { if (nwServed.contains(vnic.getL3NetworkUuid())) { VirtualRouterCommands.SNATInfo info = new VirtualRouterCommands.SNATInfo(); info.setPrivateNicIp(vnic.getIp()); info.setPrivateNicMac(vnic.getMac()); info.setPublicIp(publicNic.getIp()); info.setPublicNicMac(publicNic.getMac()); info.setSnatNetmask(vnic.getNetmask()); snatInfo.add(info); } } return snatInfo; } @Transactional protected void changeVirtualRouterNicMetaData(String vrUuid, String newL3Uuid, String oldL3Uuid) { VirtualRouterVmVO vrVo = dbf.findByUuid(vrUuid, VirtualRouterVmVO.class); for (VmNicVO nic : vrVo.getVmNics()) { if (nic.getL3NetworkUuid().equals(oldL3Uuid)) { VirtualRouterNicMetaData.removePublicToNic(nic); VirtualRouterNicMetaData.addAdditionalPublicToNic(nic); dbf.update(nic); } else if (nic.getL3NetworkUuid().equals(newL3Uuid)) { VirtualRouterNicMetaData.removeAdditionalPublicToNic(nic); VirtualRouterNicMetaData.addPublicToNic(nic); dbf.update(nic); } } } public void changeVirutalRouterDefaultL3Network(String vrUuid, String newL3Uuid, String oldL3Uuid, Completion completion) { VirtualRouterVmVO vrVo = dbf.findByUuid(vrUuid, VirtualRouterVmVO.class); VirtualRouterVmInventory vrInv = VirtualRouterVmInventory.valueOf(vrVo); VmNicVO newNic = CollectionUtils.find(vrVo.getVmNics(), new Function<VmNicVO, VmNicVO>() { @Override public VmNicVO call(VmNicVO arg) { if (arg.getL3NetworkUuid().equals(newL3Uuid)) { return arg; } return null; } }); DebugUtils.Assert(newNic != null, String.format("cannot find nic for old default network[uuid:%s]", newL3Uuid)); VirtualRouterCommands.NicInfo newNicInfo = new VirtualRouterCommands.NicInfo(); newNicInfo.setMac(newNic.getMac()); newNicInfo.setGateway(newNic.getGateway()); VirtualRouterCommands.ChangeDefaultNicCmd cmd = new VirtualRouterCommands.ChangeDefaultNicCmd(); cmd.setNewNic(newNicInfo); List<VirtualRouterCommands.SNATInfo> snatInfos = getSnatInfo(vrInv); if (snatInfos != null) { cmd.setSnats(snatInfos); } VirtualRouterAsyncHttpCallMsg msg = new VirtualRouterAsyncHttpCallMsg(); msg.setVmInstanceUuid(vrUuid); msg.setPath(VirtualRouterConstant.VR_CHANGE_DEFAULT_ROUTE_NETWORK); msg.setCommand(cmd); msg.setCheckStatus(true); bus.makeTargetServiceIdByResourceUuid(msg, VmInstanceConstant.SERVICE_ID, vrUuid); bus.send(msg, new CloudBusCallBack(completion) { @Override public void run(MessageReply reply) { if (!reply.isSuccess()) { completion.fail(reply.getError()); return; } VirtualRouterAsyncHttpCallReply re = reply.castReply(); VirtualRouterCommands.SetSNATRsp ret = re.toResponse(VirtualRouterCommands.SetSNATRsp.class); if (!ret.isSuccess()) { ErrorCode err = operr("update virtual router [uuid:%s] default network failed, because %s", vrUuid, ret.getError()); completion.fail(err); } else { changeVirtualRouterNicMetaData(vrUuid, newL3Uuid, oldL3Uuid); completion.success(); } } }); } @Override public List<VirtualRouterHaCallbackStruct> getCallback() { List<VirtualRouterHaCallbackStruct> structs = new ArrayList<>(); VirtualRouterHaCallbackStruct changeDefaultNic = new VirtualRouterHaCallbackStruct(); changeDefaultNic.type = VirtualRouterConstant.VR_CHANGE_DEFAULT_ROUTE_JOB; changeDefaultNic.callback = new VirtualRouterHaCallbackInterface() { @Override public void callBack(String vrUuid, Map<String, Object> data, Completion completion) { String newL3Uuid = (String) data.get(VirtualRouterHaCallbackInterface.Params.Struct.toString()); String oldL3Uuid = (String) data.get(VirtualRouterHaCallbackInterface.Params.Struct1.toString()); changeVirutalRouterDefaultL3Network(vrUuid, newL3Uuid, oldL3Uuid, completion); } }; structs.add(changeDefaultNic); return structs; } }