http://git-wip-us.apache.org/repos/asf/cloudstack/blob/6852f312/server/src/org/cloud/network/router/deployment/RouterDeploymentDefinition.java ---------------------------------------------------------------------- diff --git a/server/src/org/cloud/network/router/deployment/RouterDeploymentDefinition.java b/server/src/org/cloud/network/router/deployment/RouterDeploymentDefinition.java new file mode 100644 index 0000000..41ec4b3 --- /dev/null +++ b/server/src/org/cloud/network/router/deployment/RouterDeploymentDefinition.java @@ -0,0 +1,530 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.cloud.network.router.deployment; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import javax.inject.Inject; + +import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; +import org.apache.log4j.Logger; + +import com.cloud.dc.DataCenter.NetworkType; +import com.cloud.dc.HostPodVO; +import com.cloud.dc.Pod; +import com.cloud.dc.dao.HostPodDao; +import com.cloud.deploy.DataCenterDeployment; +import com.cloud.deploy.DeployDestination; +import com.cloud.deploy.DeploymentPlan; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.IpAddressManager; +import com.cloud.network.Network; +import com.cloud.network.Network.Provider; +import com.cloud.network.Network.Service; +import com.cloud.network.NetworkModel; +import com.cloud.network.Networks.BroadcastDomainType; +import com.cloud.network.Networks.IsolationType; +import com.cloud.network.Networks.TrafficType; +import com.cloud.network.PhysicalNetworkServiceProvider; +import com.cloud.network.VirtualRouterProvider; +import com.cloud.network.VirtualRouterProvider.Type; +import com.cloud.network.addr.PublicIp; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; +import com.cloud.network.dao.UserIpv6AddressDao; +import com.cloud.network.dao.VirtualRouterProviderDao; +import com.cloud.network.router.NetworkGeneralHelper; +import com.cloud.network.router.VirtualNwStatus; +import com.cloud.network.router.VirtualRouter.Role; +import com.cloud.network.router.VpcVirtualNetworkHelperImpl; +import com.cloud.network.vpc.Vpc; +import com.cloud.offering.NetworkOffering; +import com.cloud.offerings.dao.NetworkOfferingDao; +import com.cloud.service.ServiceOfferingVO; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.utils.Pair; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.JoinBuilder; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.NetUtils; +import com.cloud.vm.DomainRouterVO; +import com.cloud.vm.Nic; +import com.cloud.vm.NicProfile; +import com.cloud.vm.NicVO; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineProfile.Param; +import com.cloud.vm.dao.DomainRouterDao; +import com.cloud.vm.dao.NicDao; +import com.cloud.vm.dao.VMInstanceDao; + +public class RouterDeploymentDefinition { + private static final Logger logger = Logger.getLogger(RouterDeploymentDefinition.class); + + protected NetworkDao networkDao; + protected DomainRouterDao routerDao; + protected PhysicalNetworkServiceProviderDao physicalProviderDao; + protected NetworkModel networkModel; + protected VirtualRouterProviderDao vrProviderDao; + protected NetworkOfferingDao networkOfferingDao; + protected IpAddressManager ipAddrMgr; + protected VMInstanceDao vmDao; + protected HostPodDao podDao; + protected AccountManager accountMgr; + protected NetworkOrchestrationService networkMgr; + protected NicDao nicDao; + protected UserIpv6AddressDao ipv6Dao; + protected IPAddressDao ipAddressDao; + + + @Inject + protected NetworkGeneralHelper nwHelper; + @Inject + protected VpcVirtualNetworkHelperImpl vpcHelper; + + + protected Network guestNetwork; + protected DeployDestination dest; + protected Account owner; + protected Map<Param, Object> params; + protected boolean isRedundant; + protected DeploymentPlan plan; + protected List<DomainRouterVO> routers = new ArrayList<>(); + protected ServiceOfferingVO offering; + + + + + protected RouterDeploymentDefinition(final Network guestNetwork, final DeployDestination dest, + final Account owner, final Map<Param, Object> params, final boolean isRedundant) { + + this.guestNetwork = guestNetwork; + this.dest = dest; + this.owner = owner; + this.params = params; + this.isRedundant = isRedundant; + } + + public void setOffering(ServiceOfferingVO offering) { + this.offering = offering; + } + public Vpc getVpc() { + return null; + } + public Network getGuestNetwork() { + return guestNetwork; + } + public void setGuestNetwork(final Network guestNetwork) { + this.guestNetwork = guestNetwork; + } + public DeployDestination getDest() { + return dest; + } + public void setDest(final DeployDestination dest) { + this.dest = dest; + } + public Account getOwner() { + return owner; + } + public void setOwner(final Account owner) { + this.owner = owner; + } + public Map<Param, Object> getParams() { + return params; + } + public void setParams(final Map<Param, Object> params) { + this.params = params; + } + public boolean isRedundant() { + return isRedundant; + } + public void setRedundant(final boolean isRedundant) { + this.isRedundant = isRedundant; + } + public DeploymentPlan getPlan() { + return plan; + } + + public boolean isVpcRouter() { + return false; + } + public Pod getPod() { + return dest.getPod(); + } + public Long getPodId() { + return dest.getPod().getId(); + } + + public List<DomainRouterVO> getRouters() { + return routers; + } + public void setRouters(List<DomainRouterVO> routers) { + this.routers = routers; + } + + public boolean isBasic() { + return this.dest.getDataCenter().getNetworkType() == NetworkType.Basic; + } + + public Long getOfferingId() { + return offering == null ? null : offering.getId(); + } + + public void generateDeploymentPlan() { + final long dcId = this.dest.getDataCenter().getId(); + Long podId = null; + if (this.isBasic()) { + if (this.dest.getPod() == null) { + throw new CloudRuntimeException("Pod id is expected in deployment destination"); + } + podId = this.dest.getPod().getId(); + } + this.plan = new DataCenterDeployment(dcId, podId, null, null, null, null); + } + + + public List<DomainRouterVO> deployVirtualRouter() + throws InsufficientCapacityException, + ConcurrentOperationException, ResourceUnavailableException { + + findOrDeployVirtualRouter(); + + return nwHelper.startRouters(this); + } + + @DB + protected void findOrDeployVirtualRouter() + throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException { + + final Network lock = networkDao.acquireInLockTable(guestNetwork.getId(), NetworkOrchestrationService.NetworkLockTimeout.value()); + if (lock == null) { + throw new ConcurrentOperationException("Unable to lock network " + guestNetwork.getId()); + } + + if (logger.isDebugEnabled()) { + logger.debug("Lock is acquired for network id " + lock.getId() + " as a part of router startup in " + dest); + } + + try { + + assert guestNetwork.getState() == Network.State.Implemented || guestNetwork.getState() == Network.State.Setup || + guestNetwork.getState() == Network.State.Implementing : "Network is not yet fully implemented: " + guestNetwork; + assert guestNetwork.getTrafficType() == TrafficType.Guest; + + // 1) Get deployment plan and find out the list of routers + + // dest has pod=null, for Basic Zone findOrDeployVRs for all Pods + final List<DeployDestination> destinations = new ArrayList<DeployDestination>(); + + // for basic zone, if 'dest' has pod set to null then this is network restart scenario otherwise it is a vm deployment scenario + if (this.isBasic() && dest.getPod() == null) { + // Find all pods in the data center with running or starting user vms + final long dcId = dest.getDataCenter().getId(); + final List<HostPodVO> pods = listByDataCenterIdVMTypeAndStates(dcId, VirtualMachine.Type.User, VirtualMachine.State.Starting, VirtualMachine.State.Running); + + // Loop through all the pods skip those with running or starting VRs + for (final HostPodVO pod : pods) { + // Get list of VRs in starting or running state + final long podId = pod.getId(); + final List<DomainRouterVO> virtualRouters = routerDao.listByPodIdAndStates(podId, VirtualMachine.State.Starting, VirtualMachine.State.Running); + + assert (virtualRouters.size() <= 1) : "Pod can have utmost one VR in Basic Zone, please check!"; + + // Add virtualRouters to the routers, this avoids the situation when + // all routers are skipped and VirtualRouterElement throws exception + this.routers.addAll(virtualRouters); + + // If List size is one, we already have a starting or running VR, skip deployment + if (virtualRouters.size() == 1) { + logger.debug("Skipping VR deployment: Found a running or starting VR in Pod " + pod.getName() + " id=" + podId); + continue; + } + // Add new DeployDestination for this pod + destinations.add(new DeployDestination(dest.getDataCenter(), pod, null, null)); + } + } else { + // Else, just add the supplied dest + destinations.add(dest); + } + + // Except for Basic Zone, the for loop will iterate only once + for (final DeployDestination destination : destinations) { + this.dest = destination; + planDeploymentRouters(); + this.generateDeploymentPlan(); + + // 2) Figure out required routers count + int routerCount = 1; + if (this.isRedundant) { + routerCount = 2; + //Check current redundant routers, if possible(all routers are stopped), reset the priority + if (this.routers.size() != 0) { + checkAndResetPriorityOfRedundantRouter(this.routers); + } + } + + // If old network is redundant but new is single router, then routers.size() = 2 but routerCount = 1 + if (this.routers.size() >= routerCount) { + return; + } + + if (this.routers.size() >= 5) { + logger.error("Too much redundant routers!"); + } + + // Check if providers are supported in the physical networks + final Type type = Type.VirtualRouter; + final Long physicalNetworkId = networkModel.getPhysicalNetworkId(guestNetwork); + final PhysicalNetworkServiceProvider provider = physicalProviderDao.findByServiceProvider(physicalNetworkId, type.toString()); + if (provider == null) { + throw new CloudRuntimeException("Cannot find service provider " + type.toString() + " in physical network " + physicalNetworkId); + } + final VirtualRouterProvider vrProvider = vrProviderDao.findByNspIdAndType(provider.getId(), type); + if (vrProvider == null) { + throw new CloudRuntimeException("Cannot find virtual router provider " + type.toString() + " as service provider " + provider.getId()); + } + + if (networkModel.isNetworkSystem(guestNetwork) || guestNetwork.getGuestType() == Network.GuestType.Shared) { + this.owner = accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM); + } + + // Check if public network has to be set on VR + boolean publicNetwork = false; + if (networkModel.isProviderSupportServiceInNetwork(guestNetwork.getId(), Service.SourceNat, Provider.VirtualRouter)) { + publicNetwork = true; + } + if (this.isRedundant && !publicNetwork) { + logger.error("Didn't support redundant virtual router without public network!"); + this.routers = null; + return; + } + + Long offeringId = networkOfferingDao.findById(guestNetwork.getNetworkOfferingId()).getServiceOfferingId(); + if (offeringId == null) { + offeringId = getOfferingId(); + } + + PublicIp sourceNatIp = null; + if (publicNetwork) { + sourceNatIp = ipAddrMgr.assignSourceNatIpAddressToGuestNetwork( + this.owner, guestNetwork); + } + + // 3) deploy virtual router(s) + final int count = routerCount - this.routers.size(); + for (int i = 0; i < count; i++) { + LinkedHashMap<Network, List<? extends NicProfile>> networks = + createRouterNetworks(new Pair<Boolean, PublicIp>( + publicNetwork, sourceNatIp)); + //don't start the router as we are holding the network lock that needs to be released at the end of router allocation + DomainRouterVO router = nwHelper.deployRouter(this, vrProvider, offeringId, networks, false, null); + + if (router != null) { + routerDao.addRouterToGuestNetwork(router, guestNetwork); + this.routers.add(router); + } + } + } + } finally { + if (lock != null) { + networkDao.releaseFromLockTable(lock.getId()); + if (logger.isDebugEnabled()) { + logger.debug("Lock is released for network id " + lock.getId() + " as a part of router startup in " + dest); + } + } + } + } + + + protected List<HostPodVO> listByDataCenterIdVMTypeAndStates(final long id, final VirtualMachine.Type type, final VirtualMachine.State... states) { + final SearchBuilder<VMInstanceVO> vmInstanceSearch = vmDao.createSearchBuilder(); + vmInstanceSearch.and("type", vmInstanceSearch.entity().getType(), SearchCriteria.Op.EQ); + vmInstanceSearch.and("states", vmInstanceSearch.entity().getState(), SearchCriteria.Op.IN); + + final SearchBuilder<HostPodVO> podIdSearch = podDao.createSearchBuilder(); + podIdSearch.and("dc", podIdSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ); + podIdSearch.select(null, SearchCriteria.Func.DISTINCT, podIdSearch.entity().getId()); + podIdSearch.join("vmInstanceSearch", vmInstanceSearch, podIdSearch.entity().getId(), vmInstanceSearch.entity().getPodIdToDeployIn(), JoinBuilder.JoinType.INNER); + podIdSearch.done(); + + final SearchCriteria<HostPodVO> sc = podIdSearch.create(); + sc.setParameters("dc", id); + sc.setJoinParameters("vmInstanceSearch", "type", type); + sc.setJoinParameters("vmInstanceSearch", "states", (Object[])states); + return podDao.search(sc, null); + } + + protected void planDeploymentRouters() { + if (this.isBasic()) { + this.routers = routerDao.listByNetworkAndPodAndRole(this.guestNetwork.getId(), + this.getPodId(), Role.VIRTUAL_ROUTER); + } else { + this.routers = routerDao.listByNetworkAndRole(this.guestNetwork.getId(), + Role.VIRTUAL_ROUTER); + } + } + + private void checkAndResetPriorityOfRedundantRouter(final List<DomainRouterVO> routers) { + boolean allStopped = true; + for (final DomainRouterVO router : routers) { + if (!router.getIsRedundantRouter() || router.getState() != VirtualMachine.State.Stopped) { + allStopped = false; + break; + } + } + if (!allStopped) { + return; + } + + for (final DomainRouterVO router : routers) { + // getUpdatedPriority() would update the value later + router.setPriority(0); + router.setIsPriorityBumpUp(false); + routerDao.update(router.getId(), router); + } + } + protected LinkedHashMap<Network, List<? extends NicProfile>> createRouterNetworks( + final Pair<Boolean, PublicIp> publicNetwork) + throws ConcurrentOperationException, InsufficientAddressCapacityException { + + final Network guestNetwork = this.guestNetwork; + boolean setupPublicNetwork = false; + if (publicNetwork != null) { + setupPublicNetwork = publicNetwork.first(); + } + + //Form networks + LinkedHashMap<Network, List<? extends NicProfile>> networks = new LinkedHashMap<Network, List<? extends NicProfile>>(3); + //1) Guest network + boolean hasGuestNetwork = false; + if (guestNetwork != null) { + logger.debug("Adding nic for Virtual Router in Guest network " + guestNetwork); + String defaultNetworkStartIp = null, defaultNetworkStartIpv6 = null; + if (!setupPublicNetwork) { + final Nic placeholder = networkModel.getPlaceholderNicForRouter(guestNetwork, this.getPodId()); + if (guestNetwork.getCidr() != null) { + if (placeholder != null && placeholder.getIp4Address() != null) { + logger.debug("Requesting ipv4 address " + placeholder.getIp4Address() + " stored in placeholder nic for the network " + guestNetwork); + defaultNetworkStartIp = placeholder.getIp4Address(); + } else { + final String startIp = networkModel.getStartIpAddress(guestNetwork.getId()); + if (startIp != null && ipAddressDao.findByIpAndSourceNetworkId(guestNetwork.getId(), startIp).getAllocatedTime() == null) { + defaultNetworkStartIp = startIp; + } else if (logger.isDebugEnabled()) { + logger.debug("First ipv4 " + startIp + " in network id=" + guestNetwork.getId() + + " is already allocated, can't use it for domain router; will get random ip address from the range"); + } + } + } + + if (guestNetwork.getIp6Cidr() != null) { + if (placeholder != null && placeholder.getIp6Address() != null) { + logger.debug("Requesting ipv6 address " + placeholder.getIp6Address() + " stored in placeholder nic for the network " + guestNetwork); + defaultNetworkStartIpv6 = placeholder.getIp6Address(); + } else { + final String startIpv6 = networkModel.getStartIpv6Address(guestNetwork.getId()); + if (startIpv6 != null && ipv6Dao.findByNetworkIdAndIp(guestNetwork.getId(), startIpv6) == null) { + defaultNetworkStartIpv6 = startIpv6; + } else if (logger.isDebugEnabled()) { + logger.debug("First ipv6 " + startIpv6 + " in network id=" + guestNetwork.getId() + + " is already allocated, can't use it for domain router; will get random ipv6 address from the range"); + } + } + } + } + + final NicProfile gatewayNic = new NicProfile(defaultNetworkStartIp, defaultNetworkStartIpv6); + if (setupPublicNetwork) { + if (this.isRedundant) { + gatewayNic.setIp4Address(ipAddrMgr.acquireGuestIpAddress(guestNetwork, null)); + } else { + gatewayNic.setIp4Address(guestNetwork.getGateway()); + } + gatewayNic.setBroadcastUri(guestNetwork.getBroadcastUri()); + gatewayNic.setBroadcastType(guestNetwork.getBroadcastDomainType()); + gatewayNic.setIsolationUri(guestNetwork.getBroadcastUri()); + gatewayNic.setMode(guestNetwork.getMode()); + final String gatewayCidr = guestNetwork.getCidr(); + gatewayNic.setNetmask(NetUtils.getCidrNetmask(gatewayCidr)); + } else { + gatewayNic.setDefaultNic(true); + } + + networks.put(guestNetwork, new ArrayList<NicProfile>(Arrays.asList(gatewayNic))); + hasGuestNetwork = true; + } + + //2) Control network + logger.debug("Adding nic for Virtual Router in Control network "); + List<? extends NetworkOffering> offerings = networkModel.getSystemAccountNetworkOfferings(NetworkOffering.SystemControlNetwork); + NetworkOffering controlOffering = offerings.get(0); + Network controlConfig = networkMgr.setupNetwork(VirtualNwStatus.account, controlOffering, this.plan, + null, null, false).get(0); + networks.put(controlConfig, new ArrayList<NicProfile>()); + //3) Public network + if (setupPublicNetwork) { + final PublicIp sourceNatIp = publicNetwork.second(); + logger.debug("Adding nic for Virtual Router in Public network "); + //if source nat service is supported by the network, get the source nat ip address + final NicProfile defaultNic = new NicProfile(); + defaultNic.setDefaultNic(true); + defaultNic.setIp4Address(sourceNatIp.getAddress().addr()); + defaultNic.setGateway(sourceNatIp.getGateway()); + defaultNic.setNetmask(sourceNatIp.getNetmask()); + defaultNic.setMacAddress(sourceNatIp.getMacAddress()); + // get broadcast from public network + final Network pubNet = networkDao.findById(sourceNatIp.getNetworkId()); + if (pubNet.getBroadcastDomainType() == BroadcastDomainType.Vxlan) { + defaultNic.setBroadcastType(BroadcastDomainType.Vxlan); + defaultNic.setBroadcastUri(BroadcastDomainType.Vxlan.toUri(sourceNatIp.getVlanTag())); + defaultNic.setIsolationUri(BroadcastDomainType.Vxlan.toUri(sourceNatIp.getVlanTag())); + } else { + defaultNic.setBroadcastType(BroadcastDomainType.Vlan); + defaultNic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(sourceNatIp.getVlanTag())); + defaultNic.setIsolationUri(IsolationType.Vlan.toUri(sourceNatIp.getVlanTag())); + } + if (hasGuestNetwork) { + defaultNic.setDeviceId(2); + } + final NetworkOffering publicOffering = networkModel.getSystemAccountNetworkOfferings(NetworkOffering.SystemPublicNetwork).get(0); + final List<? extends Network> publicNetworks = networkMgr.setupNetwork(VirtualNwStatus.account, publicOffering, + this.plan, null, null, false); + final String publicIp = defaultNic.getIp4Address(); + // We want to use the identical MAC address for RvR on public interface if possible + final NicVO peerNic = nicDao.findByIp4AddressAndNetworkId(publicIp, publicNetworks.get(0).getId()); + if (peerNic != null) { + logger.info("Use same MAC as previous RvR, the MAC is " + peerNic.getMacAddress()); + defaultNic.setMacAddress(peerNic.getMacAddress()); + } + networks.put(publicNetworks.get(0), new ArrayList<NicProfile>(Arrays.asList(defaultNic))); + } + + return networks; + } + +} \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/6852f312/server/src/org/cloud/network/router/deployment/RouterDeploymentDefinitionBuilder.java ---------------------------------------------------------------------- diff --git a/server/src/org/cloud/network/router/deployment/RouterDeploymentDefinitionBuilder.java b/server/src/org/cloud/network/router/deployment/RouterDeploymentDefinitionBuilder.java new file mode 100644 index 0000000..6e2b29b --- /dev/null +++ b/server/src/org/cloud/network/router/deployment/RouterDeploymentDefinitionBuilder.java @@ -0,0 +1,188 @@ +package org.cloud.network.router.deployment; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.inject.Inject; + +import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; + +import com.cloud.dc.dao.HostPodDao; +import com.cloud.dc.dao.VlanDao; +import com.cloud.deploy.DeployDestination; +import com.cloud.network.IpAddressManager; +import com.cloud.network.Network; +import com.cloud.network.NetworkModel; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; +import com.cloud.network.dao.UserIpv6AddressDao; +import com.cloud.network.dao.VirtualRouterProviderDao; +import com.cloud.network.vpc.Vpc; +import com.cloud.network.vpc.VpcManager; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.network.vpc.dao.VpcOfferingDao; +import com.cloud.offerings.dao.NetworkOfferingDao; +import com.cloud.service.ServiceOfferingVO; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.vm.DomainRouterVO; +import com.cloud.vm.VirtualMachineProfile.Param; +import com.cloud.vm.dao.DomainRouterDao; +import com.cloud.vm.dao.NicDao; +import com.cloud.vm.dao.VMInstanceDao; + +public class RouterDeploymentDefinitionBuilder { + + @Inject + private NetworkDao networkDao; + @Inject + private DomainRouterDao routerDao = null; + @Inject + private PhysicalNetworkServiceProviderDao physicalProviderDao; + @Inject + private NetworkModel networkModel; + @Inject + private VirtualRouterProviderDao vrProviderDao; + @Inject + private NetworkOfferingDao networkOfferingDao; + @Inject + private IpAddressManager ipAddrMgr; + @Inject + private VMInstanceDao vmDao; + @Inject + private HostPodDao podDao; + @Inject + private AccountManager accountMgr; + @Inject + private NetworkOrchestrationService networkMgr; + @Inject + private NicDao nicDao; + @Inject + private UserIpv6AddressDao ipv6Dao; + @Inject + private IPAddressDao ipAddressDao; + @Inject + private VpcDao vpcDao; + @Inject + private VpcOfferingDao vpcOffDao; + @Inject + private PhysicalNetworkDao pNtwkDao; + @Inject + private VpcManager vpcMgr; + @Inject + private VlanDao vlanDao; + + protected ServiceOfferingVO offering; + + public void setOffering(ServiceOfferingVO offering) { + this.offering = offering; + } + + public IntermediateStateBuilder create() { + return new IntermediateStateBuilder(this); + } + + protected RouterDeploymentDefinition injectDependencies( + final RouterDeploymentDefinition routerDeploymentDefinition) { + + routerDeploymentDefinition.networkDao = this.networkDao; + routerDeploymentDefinition.routerDao = this.routerDao; + routerDeploymentDefinition.physicalProviderDao = this.physicalProviderDao; + routerDeploymentDefinition.networkModel = this.networkModel; + routerDeploymentDefinition.vrProviderDao = this.vrProviderDao; + routerDeploymentDefinition.networkOfferingDao = this.networkOfferingDao; + routerDeploymentDefinition.ipAddrMgr = this.ipAddrMgr; + routerDeploymentDefinition.vmDao = this.vmDao; + routerDeploymentDefinition.podDao = this.podDao; + routerDeploymentDefinition.accountMgr = this.accountMgr; + routerDeploymentDefinition.networkMgr = this.networkMgr; + routerDeploymentDefinition.nicDao = this.nicDao; + routerDeploymentDefinition.ipv6Dao = this.ipv6Dao; + routerDeploymentDefinition.ipAddressDao = this.ipAddressDao; + routerDeploymentDefinition.offering = this.offering; + + if (routerDeploymentDefinition instanceof VpcRouterDeploymentDefinition) { + this.injectVpcDependencies((VpcRouterDeploymentDefinition) routerDeploymentDefinition); + } + + return routerDeploymentDefinition; + } + + protected void injectVpcDependencies( + final VpcRouterDeploymentDefinition routerDeploymentDefinition) { + + routerDeploymentDefinition.vpcDao = this.vpcDao; + routerDeploymentDefinition.vpcOffDao = this.vpcOffDao; + routerDeploymentDefinition.pNtwkDao = this.pNtwkDao; + routerDeploymentDefinition.vpcMgr = this.vpcMgr; + routerDeploymentDefinition.vlanDao = this.vlanDao; + } + + + public class IntermediateStateBuilder { + + RouterDeploymentDefinitionBuilder builder; + + protected Vpc vpc; + protected Network guestNetwork; + protected DeployDestination dest; + protected Account owner; + protected Map<Param, Object> params; + protected boolean isRedundant; + protected List<DomainRouterVO> routers = new ArrayList<>(); + + protected IntermediateStateBuilder(RouterDeploymentDefinitionBuilder builder) { + this.builder = builder; + } + + public IntermediateStateBuilder makeRedundant() { + this.isRedundant = true; + return this; + } + + public IntermediateStateBuilder setRedundant(boolean isRedundant) { + this.isRedundant = isRedundant; + return this; + } + + public IntermediateStateBuilder setVpc(final Vpc vpc) { + this.vpc = vpc; + return this; + } + + public IntermediateStateBuilder setGuestNetwork(final Network nw) { + this.guestNetwork = nw; + return this; + } + + public IntermediateStateBuilder setAccountOwner(final Account owner) { + this.owner = owner; + return this; + } + + public IntermediateStateBuilder setDeployDestination(final DeployDestination dest) { + this.dest = dest; + return this; + } + + public IntermediateStateBuilder setParams(final Map<Param, Object> params) { + this.params = params; + return this; + } + + public RouterDeploymentDefinition build() { + RouterDeploymentDefinition routerDeploymentDefinition = null; + if (this.vpc != null) { + routerDeploymentDefinition = new VpcRouterDeploymentDefinition(vpc, dest, owner, params, isRedundant); + } else { + routerDeploymentDefinition = new RouterDeploymentDefinition(guestNetwork, dest, owner, params, isRedundant); + } + + return builder.injectDependencies(routerDeploymentDefinition); + } + } + +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/6852f312/server/src/org/cloud/network/router/deployment/VpcRouterDeploymentDefinition.java ---------------------------------------------------------------------- diff --git a/server/src/org/cloud/network/router/deployment/VpcRouterDeploymentDefinition.java b/server/src/org/cloud/network/router/deployment/VpcRouterDeploymentDefinition.java new file mode 100644 index 0000000..c592efc --- /dev/null +++ b/server/src/org/cloud/network/router/deployment/VpcRouterDeploymentDefinition.java @@ -0,0 +1,241 @@ +package org.cloud.network.router.deployment; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeSet; + +import javax.inject.Inject; + +import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; +import org.apache.log4j.Logger; + +import com.cloud.dc.dao.VlanDao; +import com.cloud.deploy.DeployDestination; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InsufficientServerCapacityException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.exception.StorageUnavailableException; +import com.cloud.network.IpAddress; +import com.cloud.network.Network; +import com.cloud.network.NetworkModel; +import com.cloud.network.Networks.BroadcastDomainType; +import com.cloud.network.Networks.IsolationType; +import com.cloud.network.PhysicalNetwork; +import com.cloud.network.PhysicalNetworkServiceProvider; +import com.cloud.network.VirtualRouterProvider; +import com.cloud.network.VirtualRouterProvider.Type; +import com.cloud.network.addr.PublicIp; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; +import com.cloud.network.dao.VirtualRouterProviderDao; +import com.cloud.network.router.VirtualNwStatus; +import com.cloud.network.vpc.PrivateGateway; +import com.cloud.network.vpc.Vpc; +import com.cloud.network.vpc.VpcManager; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.network.vpc.dao.VpcOfferingDao; +import com.cloud.offering.NetworkOffering; +import com.cloud.user.Account; +import com.cloud.utils.Pair; +import com.cloud.utils.db.DB; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.DomainRouterVO; +import com.cloud.vm.NicProfile; +import com.cloud.vm.VirtualMachineProfile.Param; + +public class VpcRouterDeploymentDefinition extends RouterDeploymentDefinition { + private static final Logger logger = Logger.getLogger(VpcRouterDeploymentDefinition.class); + + @Inject + protected VpcDao vpcDao; + @Inject + protected VpcOfferingDao vpcOffDao; + @Inject + protected PhysicalNetworkDao pNtwkDao; + @Inject + protected VpcManager vpcMgr; + @Inject + protected PhysicalNetworkServiceProviderDao physicalProviderDao; + @Inject + protected VlanDao vlanDao; + @Inject + protected IPAddressDao ipAddressDao; + @Inject + protected NetworkOrchestrationService networkMgr; + @Inject + protected NetworkModel networkModel; + @Inject + protected VirtualRouterProviderDao vrProviderDao; + + + protected Vpc vpc; + + + protected VpcRouterDeploymentDefinition(final Vpc vpc, final DeployDestination dest, final Account owner, + final Map<Param, Object> params, final boolean isRedundant) { + + super(null, dest, owner, params, isRedundant); + + this.vpc = vpc; + } + + @Override + public boolean isVpcRouter() { + return true; + } + + @Override + @DB + protected void findOrDeployVirtualRouter() + throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException { + + logger.debug("Deploying Virtual Router in VPC " + vpc); + + Vpc vpcLock = vpcDao.acquireInLockTable(vpc.getId()); + if (vpcLock == null) { + throw new ConcurrentOperationException("Unable to lock vpc " + vpc.getId()); + } + + //1) Find out the list of routers and generate deployment plan + planDeploymentRouters(); + this.generateDeploymentPlan(); + + //2) Return routers if exist, otherwise... + if (this.routers.size() < 1) { + try { + + Long offeringId = vpcOffDao.findById(vpc.getVpcOfferingId()).getServiceOfferingId(); + if (offeringId == null) { + offeringId = offering.getId(); + } + //3) Deploy Virtual Router + List<? extends PhysicalNetwork> pNtwks = pNtwkDao.listByZone(vpc.getZoneId()); + + VirtualRouterProvider vpcVrProvider = null; + + for (PhysicalNetwork pNtwk : pNtwks) { + PhysicalNetworkServiceProvider provider = physicalProviderDao.findByServiceProvider(pNtwk.getId(), Type.VPCVirtualRouter.toString()); + if (provider == null) { + throw new CloudRuntimeException("Cannot find service provider " + Type.VPCVirtualRouter.toString() + " in physical network " + pNtwk.getId()); + } + vpcVrProvider = vrProviderDao.findByNspIdAndType(provider.getId(), Type.VPCVirtualRouter); + if (vpcVrProvider != null) { + break; + } + } + + PublicIp sourceNatIp = vpcMgr.assignSourceNatIpAddressToVpc(this.owner, vpc); + + DomainRouterVO router = deployVpcRouter(vpcVrProvider, offeringId, sourceNatIp); + this.routers.add(router); + + } finally { + // TODO Should we do this after the pre or after the whole?? + if (vpcLock != null) { + vpcDao.releaseFromLockTable(vpc.getId()); + } + } + } + } + + + protected DomainRouterVO deployVpcRouter(final VirtualRouterProvider vrProvider, + final long svcOffId, final PublicIp sourceNatIp) throws ConcurrentOperationException, InsufficientAddressCapacityException, + InsufficientServerCapacityException, InsufficientCapacityException, StorageUnavailableException, ResourceUnavailableException { + + LinkedHashMap<Network, List<? extends NicProfile>> networks = createVpcRouterNetworks( + new Pair<Boolean, PublicIp>(true, sourceNatIp), this.vpc.getId()); + + DomainRouterVO router = + nwHelper.deployRouter(this, vrProvider, svcOffId, networks, true, vpcMgr.getSupportedVpcHypervisors()); + + return router; + } + + protected LinkedHashMap<Network, List<? extends NicProfile>> createVpcRouterNetworks( + final Pair<Boolean, PublicIp> sourceNatIp, final long vpcId) + throws ConcurrentOperationException, InsufficientAddressCapacityException { + + TreeSet<String> publicVlans = new TreeSet<String>(); + publicVlans.add(sourceNatIp.second().getVlanTag()); + + //1) allocate nic for control and source nat public ip + LinkedHashMap<Network, List<? extends NicProfile>> networks = nwHelper.createRouterNetworks(this, null, sourceNatIp); + + + //2) allocate nic for private gateways if needed + List<PrivateGateway> privateGateways = vpcMgr.getVpcPrivateGateways(vpcId); + if (privateGateways != null && !privateGateways.isEmpty()) { + for (PrivateGateway privateGateway : privateGateways) { + NicProfile privateNic = vpcHelper.createPrivateNicProfileForGateway(privateGateway); + Network privateNetwork = networkModel.getNetwork(privateGateway.getNetworkId()); + networks.put(privateNetwork, new ArrayList<NicProfile>(Arrays.asList(privateNic))); + } + } + + //3) allocate nic for guest gateway if needed + List<? extends Network> guestNetworks = vpcMgr.getVpcNetworks(vpcId); + for (Network guestNetwork : guestNetworks) { + if (networkModel.isPrivateGateway(guestNetwork.getId())) { + continue; + } + if (guestNetwork.getState() == Network.State.Implemented || guestNetwork.getState() == Network.State.Setup) { + NicProfile guestNic = vpcHelper.createGuestNicProfileForVpcRouter(guestNetwork); + networks.put(guestNetwork, new ArrayList<NicProfile>(Arrays.asList(guestNic))); + } + } + + //4) allocate nic for additional public network(s) + List<IPAddressVO> ips = ipAddressDao.listByAssociatedVpc(vpcId, false); + List<NicProfile> publicNics = new ArrayList<NicProfile>(); + Network publicNetwork = null; + for (IPAddressVO ip : ips) { + PublicIp publicIp = PublicIp.createFromAddrAndVlan(ip, vlanDao.findById(ip.getVlanId())); + if ((ip.getState() == IpAddress.State.Allocated || ip.getState() == IpAddress.State.Allocating) && vpcMgr.isIpAllocatedToVpc(ip) && + !publicVlans.contains(publicIp.getVlanTag())) { + logger.debug("Allocating nic for router in vlan " + publicIp.getVlanTag()); + NicProfile publicNic = new NicProfile(); + publicNic.setDefaultNic(false); + publicNic.setIp4Address(publicIp.getAddress().addr()); + publicNic.setGateway(publicIp.getGateway()); + publicNic.setNetmask(publicIp.getNetmask()); + publicNic.setMacAddress(publicIp.getMacAddress()); + publicNic.setBroadcastType(BroadcastDomainType.Vlan); + publicNic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(publicIp.getVlanTag())); + publicNic.setIsolationUri(IsolationType.Vlan.toUri(publicIp.getVlanTag())); + NetworkOffering publicOffering = networkModel.getSystemAccountNetworkOfferings(NetworkOffering.SystemPublicNetwork).get(0); + if (publicNetwork == null) { + List<? extends Network> publicNetworks = networkMgr.setupNetwork(VirtualNwStatus.account, + publicOffering, this.plan, null, null, false); + publicNetwork = publicNetworks.get(0); + } + publicNics.add(publicNic); + publicVlans.add(publicIp.getVlanTag()); + } + } + if (publicNetwork != null) { + if (networks.get(publicNetwork) != null) { + List<NicProfile> publicNicProfiles = (List<NicProfile>)networks.get(publicNetwork); + publicNicProfiles.addAll(publicNics); + networks.put(publicNetwork, publicNicProfiles); + } else { + networks.put(publicNetwork, publicNics); + } + } + + return networks; + } + + @Override + protected void planDeploymentRouters() { + this.routers = vpcHelper.getVpcRouters(this.getVpc().getId()); + } + +}