package org.zstack.simulator.virtualrouter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import org.zstack.core.thread.AsyncThread; import org.zstack.header.rest.RESTFacade; import org.zstack.network.service.virtualrouter.VirtualRouterCommands.*; import org.zstack.network.service.virtualrouter.VirtualRouterConstant; import org.zstack.network.service.virtualrouter.VirtualRouterKvmBackendCommands.CreateVritualRouterBootstrapIsoCmd; import org.zstack.network.service.virtualrouter.VirtualRouterKvmBackendCommands.CreateVritualRouterBootstrapIsoRsp; import org.zstack.network.service.virtualrouter.VirtualRouterKvmBackendCommands.DeleteVirtualRouterBootstrapIsoCmd; import org.zstack.network.service.virtualrouter.VirtualRouterKvmBackendCommands.DeleteVirtualRouterBootstrapIsoRsp; import org.zstack.network.service.virtualrouter.lb.VirtualRouterLoadBalancerBackend; import org.zstack.network.service.virtualrouter.lb.VirtualRouterLoadBalancerBackend.DeleteLbCmd; import org.zstack.network.service.virtualrouter.lb.VirtualRouterLoadBalancerBackend.DeleteLbRsp; import org.zstack.network.service.virtualrouter.lb.VirtualRouterLoadBalancerBackend.RefreshLbCmd; import org.zstack.network.service.virtualrouter.lb.VirtualRouterLoadBalancerBackend.RefreshLbRsp; import org.zstack.simulator.AsyncRESTReplyer; import org.zstack.simulator.SimulatorGlobalProperty; import org.zstack.utils.Utils; import org.zstack.utils.gson.JSONObjectUtil; import org.zstack.utils.logging.CLogger; import javax.servlet.http.HttpServletRequest; @Controller public class VirtualRouterSimulator { CLogger logger = Utils.getLogger(VirtualRouterSimulator.class); @Autowired private RESTFacade restf; @Autowired private VirtualRouterSimulatorConfig config; private AsyncRESTReplyer replyer = new AsyncRESTReplyer(); @AsyncThread private void doSetDhcpEntry(HttpEntity<String> entity) { AddDhcpEntryCmd cmd = JSONObjectUtil.toObject(entity.getBody(), AddDhcpEntryCmd.class); AddDhcpEntryRsp rsp = new AddDhcpEntryRsp(); if (!config.setDhcpEntrySuccess) { rsp.setError("fail on purpose"); rsp.setSuccess(false); replyer.reply(entity, rsp); return; } if (cmd.isRebuild()) { config.dhcpInfos.clear(); } if (!SimulatorGlobalProperty.NOT_CACHE_AGENT_COMMAND) { config.dhcpInfos.addAll(cmd.getDhcpEntries()); for (DhcpInfo info : cmd.getDhcpEntries()) { config.dhcpInfoMap.put(info.getMac(), info); } } logger.debug(String.format("successfully set dhcp entries: %s", JSONObjectUtil.toJsonString(cmd.getDhcpEntries()))); replyer.reply(entity, rsp); } @RequestMapping(value = VirtualRouterConstant.VR_INIT, method = RequestMethod.POST) private @ResponseBody String init(HttpServletRequest req) { HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req); doInit(entity); return null; } private void doInit(HttpEntity<String> entity) { InitCommand cmd = JSONObjectUtil.toObject(entity.getBody(), InitCommand.class); config.initCommands.add(cmd); config.uuid = cmd.getUuid(); replyer.reply(entity, new InitRsp()); } @RequestMapping(value = VirtualRouterConstant.VR_ADD_DHCP_PATH, method = RequestMethod.POST) private @ResponseBody String setDhcpEntry(HttpServletRequest req) { HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req); doSetDhcpEntry(entity); return null; } @RequestMapping(value = VirtualRouterConstant.VR_REVOKE_PORT_FORWARDING, method = RequestMethod.POST) private @ResponseBody String revokePortForwardingRules(HttpServletRequest req) { HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req); doRevokePortForwardingRules(entity); return null; } @RequestMapping(value = VirtualRouterConstant.VR_CREATE_EIP, method = RequestMethod.POST) private @ResponseBody String createEip(HttpServletRequest req) { HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req); createEip(entity); return null; } @AsyncThread private void createEip(HttpEntity<String> entity) { CreateEipCmd cmd = JSONObjectUtil.toObject(entity.getBody(), CreateEipCmd.class); CreateEipRsp rsp = new CreateEipRsp(); if (config.eipSuccess) { if (!SimulatorGlobalProperty.NOT_CACHE_AGENT_COMMAND) { config.eips.add(cmd.getEip()); } } else { rsp.setError("on purpose"); rsp.setSuccess(false); } replyer.reply(entity, rsp); } @RequestMapping(value = VirtualRouterConstant.VR_REMOVE_EIP, method = RequestMethod.POST) private @ResponseBody String removeEip(HttpServletRequest req) { HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req); removeEip(entity); return null; } @AsyncThread private void removeEip(HttpEntity<String> entity) { RemoveEipCmd cmd = JSONObjectUtil.toObject(entity.getBody(), RemoveEipCmd.class); RemoveEipRsp rsp = new RemoveEipRsp(); if (config.removeEipSuccess) { if (!SimulatorGlobalProperty.NOT_CACHE_AGENT_COMMAND) { config.removedEips.add(cmd.getEip()); } } else { rsp.setSuccess(false); rsp.setError("on purpose"); } replyer.reply(entity, rsp); } @RequestMapping(value = VirtualRouterConstant.VR_SYNC_EIP, method = RequestMethod.POST) private @ResponseBody String syncEip(HttpServletRequest req) { HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req); syncEip(entity); return null; } @AsyncThread private void syncEip(HttpEntity<String> entity) { SyncEipCmd cmd = JSONObjectUtil.toObject(entity.getBody(), SyncEipCmd.class); SyncEipRsp rsp = new SyncEipRsp(); if (config.syncEipSuccess) { config.eips.clear(); if (!SimulatorGlobalProperty.NOT_CACHE_AGENT_COMMAND) { config.eips.addAll(cmd.getEips()); } } else { rsp.setError("on purpose"); rsp.setSuccess(false); } replyer.reply(entity, rsp); } @AsyncThread private void doRevokePortForwardingRules(HttpEntity<String> entity) { RevokePortForwardingRuleCmd cmd = JSONObjectUtil.toObject(entity.getBody(), RevokePortForwardingRuleCmd.class); RevokePortForwardingRuleRsp rsp = new RevokePortForwardingRuleRsp(); if (!config.portForwardingSuccess) { rsp.setError("failed on purpose"); rsp.setSuccess(false); } else { logger.debug(String.format("successfully removed port forwarding rules:\n%s", JSONObjectUtil.toJsonString(cmd.getRules()))); config.removedPortForwardingRules.addAll(cmd.getRules()); } replyer.reply(entity, rsp); } @RequestMapping(value = VirtualRouterConstant.VR_CREATE_VIP, method = RequestMethod.POST) private @ResponseBody String createVip(HttpServletRequest req) { HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req); doCreateVip(entity); return null; } @AsyncThread private void doCreateVip(HttpEntity<String> entity) { CreateVipCmd cmd = JSONObjectUtil.toObject(entity.getBody(), CreateVipCmd.class); CreateVipRsp rsp = new CreateVipRsp(); if (!config.vipSuccess) { rsp.setError("failed on purpose"); rsp.setSuccess(false); } else { if (!SimulatorGlobalProperty.NOT_CACHE_AGENT_COMMAND) { config.vips.addAll(cmd.getVips()); } logger.debug(String.format("successfully created vips %s", JSONObjectUtil.toJsonString(cmd.getVips()))); } replyer.reply(entity, rsp); } @RequestMapping(value = VirtualRouterConstant.VR_REMOVE_VIP, method = RequestMethod.POST) private @ResponseBody String removeVip(HttpServletRequest req) { HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req); doRemoveVip(entity); return null; } @AsyncThread private void doRemoveVip(HttpEntity<String> entity) { RemoveVipCmd cmd = JSONObjectUtil.toObject(entity.getBody(), RemoveVipCmd.class); RemoveVipRsp rsp = new RemoveVipRsp(); if (!SimulatorGlobalProperty.NOT_CACHE_AGENT_COMMAND) { config.removedVips.addAll(cmd.getVips()); } logger.debug(String.format("successfully removed vips %s", JSONObjectUtil.toJsonString(cmd.getVips()))); replyer.reply(entity, rsp); } @RequestMapping(value = VirtualRouterConstant.VR_SYNC_PORT_FORWARDING, method = RequestMethod.POST) private @ResponseBody String syncPortForwardingRules(HttpServletRequest req) { HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req); doSyncPortForwardingRules(entity); return null; } private void doSyncPortForwardingRules(HttpEntity<String> entity) { SyncPortForwardingRuleCmd cmd = JSONObjectUtil.toObject(entity.getBody(), SyncPortForwardingRuleCmd.class); SyncPortForwardingRuleRsp rsp = new SyncPortForwardingRuleRsp(); if (!config.portForwardingSuccess) { rsp.setError("failed on purpose"); rsp.setSuccess(false); } else { config.portForwardingRules.clear(); if (!SimulatorGlobalProperty.NOT_CACHE_AGENT_COMMAND) { config.portForwardingRules.addAll(cmd.getRules()); } logger.debug(String.format("successfully synced port forwarding rules: \n%s", JSONObjectUtil.toJsonString(cmd.getRules()))); } replyer.reply(entity, rsp); } @RequestMapping(value = VirtualRouterConstant.VR_CREATE_PORT_FORWARDING, method = RequestMethod.POST) private @ResponseBody String createPortForwardingRules(HttpServletRequest req) { HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req); doCreatePortForwardingRules(entity); return null; } @AsyncThread private void doCreatePortForwardingRules(HttpEntity<String> entity) { CreatePortForwardingRuleCmd cmd = JSONObjectUtil.toObject(entity.getBody(), CreatePortForwardingRuleCmd.class); CreatePortForwardingRuleRsp rsp = new CreatePortForwardingRuleRsp(); if (!config.portForwardingSuccess) { rsp.setError("failed on purpose"); rsp.setSuccess(false); } else { if (!SimulatorGlobalProperty.NOT_CACHE_AGENT_COMMAND) { config.portForwardingRules.addAll(cmd.getRules()); } logger.debug(String.format("successfully added port forwarding rules:\n%s", JSONObjectUtil.toJsonString(cmd.getRules()))); } replyer.reply(entity, rsp); } @RequestMapping(value = VirtualRouterConstant.VR_ECHO_PATH, method = RequestMethod.POST) private @ResponseBody String echo(HttpServletRequest req) { logger.debug("virtual router connected"); return null; } @RequestMapping(value = VirtualRouterConstant.VR_PING, method = RequestMethod.POST) private @ResponseBody String ping(HttpServletRequest req) { HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req); PingCmd cmd = JSONObjectUtil.toObject(entity.getBody(), PingCmd.class); config.pingCmds.add(cmd); PingRsp rsp = new PingRsp(); rsp.setUuid(config.uuid); replyer.reply(entity, rsp); return null; } @RequestMapping(value = VirtualRouterConstant.VR_SYNC_SNAT_PATH, method = RequestMethod.POST) private @ResponseBody String syncSNAT(HttpServletRequest req) { HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req); syncSNAT(entity); return null; } @AsyncThread private void syncSNAT(HttpEntity<String> entity) { SyncSNATCmd cmd = JSONObjectUtil.toObject(entity.getBody(), SyncSNATCmd.class); SyncSNATRsp rsp = new SyncSNATRsp(); if (!config.setSNATSuccess) { rsp.setError("fail on purpose"); rsp.setSuccess(false); } else { config.snatInfos.clear(); if (!SimulatorGlobalProperty.NOT_CACHE_AGENT_COMMAND) { config.snatInfos.addAll(cmd.getSnats()); } logger.debug(String.format("successfully sync snats: %s", JSONObjectUtil.toJsonString(cmd.getSnats()))); } replyer.reply(entity, rsp); } @RequestMapping(value = VirtualRouterLoadBalancerBackend.REFRESH_LB_PATH, method = RequestMethod.POST) private @ResponseBody String refreshLb(HttpServletRequest req) { HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req); RefreshLbCmd cmd = JSONObjectUtil.toObject(entity.getBody(), RefreshLbCmd.class); RefreshLbRsp rsp = new RefreshLbRsp(); if (!config.refreshLbSuccess) { rsp.setError("on purpose"); rsp.setSuccess(false); } else { config.refreshLbCmds.add(cmd); } replyer.reply(entity, rsp); return null; } @RequestMapping(value = VirtualRouterLoadBalancerBackend.DELETE_LB_PATH, method = RequestMethod.POST) private @ResponseBody String deleteLb(HttpServletRequest req) { HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req); DeleteLbCmd cmd = JSONObjectUtil.toObject(entity.getBody(), DeleteLbCmd.class); DeleteLbRsp rsp = new DeleteLbRsp(); config.deleteLbCmds.add(cmd); replyer.reply(entity, rsp); return null; } @RequestMapping(value = VirtualRouterConstant.VR_SET_SNAT_PATH, method = RequestMethod.POST) private @ResponseBody String setSNAT(HttpServletRequest req) { HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req); doSetSNAT(entity); return null; } @AsyncThread private void doSetSNAT(HttpEntity<String> entity) { SetSNATCmd cmd = JSONObjectUtil.toObject(entity.getBody(), SetSNATCmd.class); SetSNATRsp rsp = new SetSNATRsp(); if (!config.setSNATSuccess) { rsp.setError("fail on purpose"); rsp.setSuccess(false); replyer.reply(entity, rsp); return; } if (!SimulatorGlobalProperty.NOT_CACHE_AGENT_COMMAND) { config.snatInfos.add(cmd.getSnat()); } logger.debug(String.format("successfully set snat: %s", JSONObjectUtil.toJsonString(cmd.getSnat()))); replyer.reply(entity, rsp); } @RequestMapping(value = VirtualRouterConstant.VR_REMOVE_DNS_PATH, method = RequestMethod.POST) private @ResponseBody String removeDNS(HttpServletRequest req) { HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req); RemoveDnsCmd cmd = JSONObjectUtil.toObject(entity.getBody(), RemoveDnsCmd.class); config.removeDnsCmds.add(cmd); replyer.reply(entity, new RemoveDnsRsp()); return null; } @RequestMapping(value = VirtualRouterConstant.VR_SET_DNS_PATH, method = RequestMethod.POST) private @ResponseBody String setDNS(HttpServletRequest req) { HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req); doSetDNS(entity); return null; } private void doSetDNS(HttpEntity<String> entity) { SetDnsCmd cmd = JSONObjectUtil.toObject(entity.getBody(), SetDnsCmd.class); SetDnsRsp rsp = new SetDnsRsp(); if (!config.setDnsSuccess) { rsp.setError("fail on purpose"); rsp.setSuccess(true); replyer.reply(entity, rsp); return; } config.dnsInfo.clear(); if (!SimulatorGlobalProperty.NOT_CACHE_AGENT_COMMAND) { config.dnsInfo.addAll(cmd.getDns()); } logger.debug(String.format("successfully configured dns: %s", JSONObjectUtil.toJsonString(cmd.getDns()))); replyer.reply(entity, rsp); } @AsyncThread private void doConfigureNic(HttpEntity<String> entity) { ConfigureNicCmd cmd = JSONObjectUtil.toObject(entity.getBody(), ConfigureNicCmd.class); ConfigureNicRsp rsp = new ConfigureNicRsp(); if (!config.configureNicSuccess) { rsp.setError("fail on purpose"); rsp.setSuccess(false); replyer.reply(entity, rsp); return; } logger.debug(String.format("successfully configured nics: %s", JSONObjectUtil.toJsonString(cmd.getNics()))); replyer.reply(entity, rsp); return; } @RequestMapping(value = VirtualRouterConstant.VR_CONFIGURE_NIC_PATH, method = RequestMethod.POST) private @ResponseBody String configureNic(HttpServletRequest req) { HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req); doConfigureNic(entity); return null; } @RequestMapping(value = VirtualRouterConstant.VR_REMOVE_DHCP_PATH, method = RequestMethod.POST) private @ResponseBody String removeDchpEntry(HttpServletRequest req) { HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req); doRemoveDhcpEntry(entity); return null; } @RequestMapping(value = VirtualRouterConstant.VR_KVM_CREATE_BOOTSTRAP_ISO_PATH, method = RequestMethod.POST) private @ResponseBody String prepareIso(HttpServletRequest req) { HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req); doPrepareIso(entity); return null; } @RequestMapping(value = VirtualRouterConstant.VR_KVM_DELETE_BOOTSTRAP_ISO_PATH, method = RequestMethod.POST) private @ResponseBody String deleteIso(HttpServletRequest req) { HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req); doDeleteIso(entity); return null; } private void doDeleteIso(HttpEntity<String> entity) { DeleteVirtualRouterBootstrapIsoCmd cmd = JSONObjectUtil.toObject(entity.getBody(), DeleteVirtualRouterBootstrapIsoCmd.class); logger.debug(String.format("successfully deleted iso at %s", cmd.getIsoPath())); DeleteVirtualRouterBootstrapIsoRsp rsp = new DeleteVirtualRouterBootstrapIsoRsp(); replyer.reply(entity, rsp); } private void doPrepareIso(HttpEntity<String> entity) { CreateVritualRouterBootstrapIsoCmd cmd = JSONObjectUtil.toObject(entity.getBody(), CreateVritualRouterBootstrapIsoCmd.class); logger.debug(String.format("successfully create iso at %s, %s", cmd.getIsoPath(), JSONObjectUtil.toJsonString(cmd.getIsoInfo()))); CreateVritualRouterBootstrapIsoRsp rsp = new CreateVritualRouterBootstrapIsoRsp(); replyer.reply(entity, rsp); } private void doRemoveDhcpEntry(HttpEntity<String> entity) { RemoveDhcpEntryRsp rsp = new RemoveDhcpEntryRsp(); if (config.removedDhcpSuccess) { RemoveDhcpEntryCmd cmd = JSONObjectUtil.toObject(entity.getBody(), RemoveDhcpEntryCmd.class); if (!SimulatorGlobalProperty.NOT_CACHE_AGENT_COMMAND) { config.removedDhcp.addAll(cmd.getDhcpEntries()); } logger.debug(String.format("successfully removed dhcp entries: %s", JSONObjectUtil.toJsonString(cmd.getDhcpEntries()))); } else { String err = "failed to remove dhcp on purpose"; logger.debug(err); rsp.setError(err); rsp.setSuccess(false); } replyer.reply(entity, rsp); } @ExceptionHandler(Exception.class) public ModelAndView handleAllException(Exception ex) { logger.warn(ex.getMessage(), ex); ModelAndView model = new ModelAndView("error/generic_error"); model.addObject("errMsg", ex.getMessage()); return model; } }