package org.zstack.network.service.virtualrouter.vyos; import org.springframework.beans.factory.annotation.Autowired; import org.zstack.appliancevm.*; import org.zstack.core.Platform; import org.zstack.core.ansible.AnsibleFacade; import org.zstack.core.componentloader.PluginRegistry; import org.zstack.core.config.GlobalConfigException; import org.zstack.core.config.GlobalConfigValidatorExtensionPoint; import org.zstack.core.db.DatabaseFacade; import org.zstack.core.db.SimpleQuery; import org.zstack.core.db.SimpleQuery.Op; import org.zstack.core.workflow.FlowChainBuilder; import org.zstack.header.Component; import org.zstack.header.core.workflow.Flow; import org.zstack.header.core.workflow.FlowChain; import org.zstack.header.errorcode.OperationFailureException; import org.zstack.header.managementnode.PrepareDbInitialValueExtensionPoint; 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.service.NetworkServiceProviderL2NetworkRefVO; import org.zstack.header.network.service.NetworkServiceProviderVO; import org.zstack.header.network.service.NetworkServiceProviderVO_; import org.zstack.header.network.service.NetworkServiceType; import org.zstack.header.vm.VmInstanceSpec; import org.zstack.network.service.eip.EipConstant; import org.zstack.network.service.lb.LoadBalancerConstants; import org.zstack.network.service.virtualrouter.VirtualRouterApplianceVmFactory; import org.zstack.network.service.virtualrouter.VirtualRouterGlobalConfig; import org.zstack.network.service.virtualrouter.VirtualRouterVmVO; import org.zstack.utils.Utils; import org.zstack.utils.logging.CLogger; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * Created by xing5 on 2016/10/31. */ public class VyosVmFactory extends VirtualRouterApplianceVmFactory implements Component, PrepareDbInitialValueExtensionPoint, L2NetworkCreateExtensionPoint, ApplianceVmPrepareBootstrapInfoExtensionPoint { private static final CLogger logger = Utils.getLogger(VyosVmFactory.class); public static ApplianceVmType type = new ApplianceVmType(VyosConstants.VYOS_VM_TYPE); @Autowired private AnsibleFacade asf; @Autowired private DatabaseFacade dbf; @Autowired private PluginRegistry pluginRgty; private List<String> vyosPostCreateFlows; private List<String> vyosPostStartFlows; private List<String> vyosPostRebootFlows; private List<String> vyosPostDestroyFlows; private List<String> vyosReconnectFlows; private FlowChainBuilder postCreateFlowsBuilder; private FlowChainBuilder postStartFlowsBuilder; private FlowChainBuilder postRebootFlowsBuilder; private FlowChainBuilder postDestroyFlowsBuilder; private FlowChainBuilder reconnectFlowsBuilder; private NetworkServiceProviderVO providerVO; private List<VyosPostCreateFlowExtensionPoint> postCreateFlowExtensionPoints; private List<VyosPostDestroyFlowExtensionPoint> postDestroyFlowExtensionPoints; private List<VyosPostRebootFlowExtensionPoint> postRebootFlowExtensionPoints; private List<VyosPostReconnectFlowExtensionPoint> postReconnectFlowExtensionPoints; private List<VyosPostStartFlowExtensionPoint> postStartFlowExtensionPoints; private final static List<String> supportedL2NetworkTypes = new ArrayList<>(); static { supportedL2NetworkTypes.add(L2NetworkConstant.L2_NO_VLAN_NETWORK_TYPE); supportedL2NetworkTypes.add(L2NetworkConstant.L2_VLAN_NETWORK_TYPE); } public void setVyosPostCreateFlows(List<String> vyosPostCreateFlows) { this.vyosPostCreateFlows = vyosPostCreateFlows; } public void setVyosPostStartFlows(List<String> vyosPostStartFlows) { this.vyosPostStartFlows = vyosPostStartFlows; } public void setVyosPostRebootFlows(List<String> vyosPostRebootFlows) { this.vyosPostRebootFlows = vyosPostRebootFlows; } public void setVyosPostDestroyFlows(List<String> vyosPostDestroyFlows) { this.vyosPostDestroyFlows = vyosPostDestroyFlows; } public void setVyosReconnectFlows(List<String> vyosReconnectFlows) { this.vyosReconnectFlows = vyosReconnectFlows; } public List<Flow> getPostCreateFlows() { List<Flow> flows = new ArrayList<>(); flows.addAll(postCreateFlowsBuilder.getFlows()); flows.addAll(postCreateFlowExtensionPoints.stream().map(VyosPostCreateFlowExtensionPoint::vyosPostCreateFlow).collect(Collectors.toList())); return flows; } public List<Flow> getPostStartFlows() { List<Flow> flows = new ArrayList<>(); flows.addAll(postStartFlowsBuilder.getFlows()); flows.addAll(postStartFlowExtensionPoints.stream().map(VyosPostStartFlowExtensionPoint::vyosPostStartFlow).collect(Collectors.toList())); return flows; } public List<Flow> getPostRebootFlows() { List<Flow> flows = new ArrayList<>(); flows.addAll(postRebootFlowsBuilder.getFlows()); flows.addAll(postRebootFlowExtensionPoints.stream().map(VyosPostRebootFlowExtensionPoint::vyosPostRebootFlow).collect(Collectors.toList())); return flows; } public List<Flow> getPostStopFlows() { return null; } public List<Flow> getPostMigrateFlows() { return null; } public List<Flow> getPostDestroyFlows() { List<Flow> flows = new ArrayList<>(); flows.addAll(postDestroyFlowsBuilder.getFlows()); flows.addAll(postDestroyFlowExtensionPoints.stream().map(VyosPostDestroyFlowExtensionPoint::vyosPostDestroyFlow).collect(Collectors.toList())); return flows; } public FlowChain getReconnectFlowChain() { FlowChain c = reconnectFlowsBuilder.build(); for (VyosPostReconnectFlowExtensionPoint ext : postReconnectFlowExtensionPoints) { c.then(ext.vyosPostReconnectFlow()); } return c; } @Override public ApplianceVmType getApplianceVmType() { return type; } @Override public ApplianceVm getSubApplianceVm(ApplianceVmVO apvm) { VirtualRouterVmVO vr = dbf.findByUuid(apvm.getUuid(), VirtualRouterVmVO.class); return new VyosVm(vr); } private void buildWorkFlowBuilder() { postCreateFlowsBuilder = FlowChainBuilder.newBuilder().setFlowClassNames(vyosPostCreateFlows).construct(); postStartFlowsBuilder = FlowChainBuilder.newBuilder().setFlowClassNames(vyosPostStartFlows).construct(); postRebootFlowsBuilder = FlowChainBuilder.newBuilder().setFlowClassNames(vyosPostRebootFlows).construct(); postDestroyFlowsBuilder = FlowChainBuilder.newBuilder().setFlowClassNames(vyosPostDestroyFlows).construct(); reconnectFlowsBuilder = FlowChainBuilder.newBuilder().setFlowClassNames(vyosReconnectFlows).construct(); } @Override public boolean start() { buildWorkFlowBuilder(); populateExtensions(); VirtualRouterGlobalConfig.VYOS_PASSWORD.installValidateExtension(new GlobalConfigValidatorExtensionPoint() { @Override public void validateGlobalConfig(String category, String name, String oldValue, String newValue) throws GlobalConfigException { if (!newValue.matches("^[a-zA-Z0-9][A-Za-z0-9-_#]*")) { throw new GlobalConfigException("the vrouter password's first character must be a letter or number, besides no characters other than letters, numbers and these special characters: -_#"); } } }); return true; } private void populateExtensions() { postCreateFlowExtensionPoints = pluginRgty.getExtensionList(VyosPostCreateFlowExtensionPoint.class); postDestroyFlowExtensionPoints = pluginRgty.getExtensionList(VyosPostDestroyFlowExtensionPoint.class); postRebootFlowExtensionPoints = pluginRgty.getExtensionList(VyosPostRebootFlowExtensionPoint.class); postReconnectFlowExtensionPoints = pluginRgty.getExtensionList(VyosPostReconnectFlowExtensionPoint.class); postStartFlowExtensionPoints = pluginRgty.getExtensionList(VyosPostStartFlowExtensionPoint.class); } @Override public boolean stop() { return true; } @Override public void prepareDbInitialValue() { SimpleQuery<NetworkServiceProviderVO> query = dbf.createQuery(NetworkServiceProviderVO.class); query.add(NetworkServiceProviderVO_.type, Op.EQ, VyosConstants.VYOS_ROUTER_PROVIDER_TYPE); providerVO = query.find(); if (providerVO != null) { return; } NetworkServiceProviderVO vo = new NetworkServiceProviderVO(); vo.setUuid(Platform.getUuid()); vo.setName(VyosConstants.VYOS_VM_TYPE); vo.setDescription("zstack vrouter 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); //hard code for the premium plugin vo.getNetworkServiceTypes().add("IPsec"); vo.setType(VyosConstants.VYOS_ROUTER_PROVIDER_TYPE); providerVO = dbf.persistAndRefresh(vo); } @Override public void beforeCreateL2Network(APICreateL2NetworkMsg msg) throws NetworkException { } @Override public void afterCreateL2Network(L2NetworkInventory l2Network) { if (!supportedL2NetworkTypes.contains(l2Network.getType())) { return; } NetworkServiceProviderL2NetworkRefVO ref = new NetworkServiceProviderL2NetworkRefVO(); ref.setNetworkServiceProviderUuid(providerVO.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]", providerVO.getUuid(), providerVO.getName(), providerVO.getType(), l2Network.getUuid(), l2Network.getName(), l2Network.getType()); logger.debug(info); } public String getNetworkServiceProviderUuid() { return providerVO.getUuid(); } @Override public void applianceVmPrepareBootstrapInfo(VmInstanceSpec spec, Map<String, Object> info) { SimpleQuery<ApplianceVmVO> q = dbf.createQuery(ApplianceVmVO.class); q.add(ApplianceVmVO_.applianceVmType, Op.EQ, VyosConstants.VYOS_VM_TYPE); q.add(ApplianceVmVO_.uuid, Op.EQ, spec.getVmInventory().getUuid()); if (!q.isExists()) { return; } info.put(VyosConstants.BootstrapInfoKey.vyosPassword.toString(), VirtualRouterGlobalConfig.VYOS_PASSWORD.value()); } }