diff --git a/api/src/com/cloud/network/element/FirewallServiceProvider.java b/api/src/com/cloud/network/element/FirewallServiceProvider.java index 6600831db77..6f65a0a6928 100644 --- a/api/src/com/cloud/network/element/FirewallServiceProvider.java +++ b/api/src/com/cloud/network/element/FirewallServiceProvider.java @@ -4,7 +4,6 @@ import java.util.List; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.Network; -import com.cloud.network.PublicIpAddress; import com.cloud.network.rules.FirewallRule; public interface FirewallServiceProvider extends NetworkElement { @@ -16,13 +15,4 @@ public interface FirewallServiceProvider extends NetworkElement { * @throws ResourceUnavailableException */ boolean applyFWRules(Network network, List rules) throws ResourceUnavailableException; - - /** - * Apply ip addresses to this network - * @param network - * @param ipAddress - * @return - * @throws ResourceUnavailableException - */ - boolean applyIps(Network network, List ipAddress) throws ResourceUnavailableException; } diff --git a/api/src/com/cloud/network/element/IpDeployer.java b/api/src/com/cloud/network/element/IpDeployer.java new file mode 100644 index 00000000000..1e458da14d9 --- /dev/null +++ b/api/src/com/cloud/network/element/IpDeployer.java @@ -0,0 +1,20 @@ +package com.cloud.network.element; + +import java.util.List; +import java.util.Set; + +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.Network; +import com.cloud.network.Network.Service; +import com.cloud.network.PublicIpAddress; + +public interface IpDeployer { + /** + * Apply ip addresses to this network + * @param network + * @param ipAddress + * @return + * @throws ResourceUnavailableException + */ + boolean applyIps(Network network, List ipAddress, Set services) throws ResourceUnavailableException; +} diff --git a/api/src/com/cloud/network/element/LoadBalancingServiceProvider.java b/api/src/com/cloud/network/element/LoadBalancingServiceProvider.java index 7d31f3cd7fe..d1f3dc65de9 100644 --- a/api/src/com/cloud/network/element/LoadBalancingServiceProvider.java +++ b/api/src/com/cloud/network/element/LoadBalancingServiceProvider.java @@ -4,7 +4,6 @@ import java.util.List; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.Network; -import com.cloud.network.PublicIpAddress; import com.cloud.network.lb.LoadBalancingRule; public interface LoadBalancingServiceProvider extends NetworkElement { @@ -17,12 +16,5 @@ public interface LoadBalancingServiceProvider extends NetworkElement { */ boolean applyLBRules(Network network, List rules) throws ResourceUnavailableException; - /** - * Apply ip addresses to this network service provider - * @param network - * @param ipAddress - * @return - * @throws ResourceUnavailableException - */ - boolean applyLoadBalancerIp(Network network, List ipAddress) throws ResourceUnavailableException; + IpDeployer getIpDeployer(Network network); } diff --git a/api/src/com/cloud/network/element/PortForwardingServiceProvider.java b/api/src/com/cloud/network/element/PortForwardingServiceProvider.java index 2bcdc8c7fa0..4437a9645c7 100644 --- a/api/src/com/cloud/network/element/PortForwardingServiceProvider.java +++ b/api/src/com/cloud/network/element/PortForwardingServiceProvider.java @@ -4,7 +4,6 @@ import java.util.List; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.Network; -import com.cloud.network.PublicIpAddress; import com.cloud.network.rules.PortForwardingRule; public interface PortForwardingServiceProvider extends NetworkElement { @@ -17,12 +16,5 @@ public interface PortForwardingServiceProvider extends NetworkElement { */ boolean applyPFRules(Network network, List rules) throws ResourceUnavailableException; - /** - * Apply ip addresses to this network service provider - * @param network - * @param ipAddress - * @return - * @throws ResourceUnavailableException - */ - boolean applyIps(Network network, List ipAddress) throws ResourceUnavailableException; + IpDeployer getIpDeployer(Network network); } diff --git a/api/src/com/cloud/network/element/RemoteAccessVPNServiceProvider.java b/api/src/com/cloud/network/element/RemoteAccessVPNServiceProvider.java index 522a4593a5d..57d44e89f46 100644 --- a/api/src/com/cloud/network/element/RemoteAccessVPNServiceProvider.java +++ b/api/src/com/cloud/network/element/RemoteAccessVPNServiceProvider.java @@ -13,4 +13,6 @@ public interface RemoteAccessVPNServiceProvider extends NetworkElement { boolean startVpn(Network network, RemoteAccessVpn vpn) throws ResourceUnavailableException; boolean stopVpn(Network network, RemoteAccessVpn vpn) throws ResourceUnavailableException; + + IpDeployer getIpDeployer(Network network); } diff --git a/api/src/com/cloud/network/element/SourceNatServiceProvider.java b/api/src/com/cloud/network/element/SourceNatServiceProvider.java index f42c445997c..3c91a683467 100644 --- a/api/src/com/cloud/network/element/SourceNatServiceProvider.java +++ b/api/src/com/cloud/network/element/SourceNatServiceProvider.java @@ -1,19 +1,7 @@ package com.cloud.network.element; -import java.util.List; - -import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.Network; -import com.cloud.network.PublicIpAddress; public interface SourceNatServiceProvider extends NetworkElement { - - /** - * Apply ip addresses to this network - * @param network - * @param ipAddress - * @return - * @throws ResourceUnavailableException - */ - boolean applyIps(Network network, List ipAddress) throws ResourceUnavailableException; + IpDeployer getIpDeployer(Network network); } diff --git a/api/src/com/cloud/network/element/StaticNatServiceProvider.java b/api/src/com/cloud/network/element/StaticNatServiceProvider.java index c5c0608fe76..74da0718917 100644 --- a/api/src/com/cloud/network/element/StaticNatServiceProvider.java +++ b/api/src/com/cloud/network/element/StaticNatServiceProvider.java @@ -4,7 +4,6 @@ import java.util.List; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.Network; -import com.cloud.network.PublicIpAddress; import com.cloud.network.rules.StaticNat; public interface StaticNatServiceProvider extends NetworkElement { @@ -17,12 +16,5 @@ public interface StaticNatServiceProvider extends NetworkElement { */ boolean applyStaticNats(Network config, List rules) throws ResourceUnavailableException; - /** - * Apply ip addresses to this network service provider - * @param network - * @param ipAddress - * @return - * @throws ResourceUnavailableException - */ - boolean applyIps(Network network, List ipAddress) throws ResourceUnavailableException; + IpDeployer getIpDeployer(Network network); } diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index 747bbff4538..7192c9fcf48 100644 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -19,6 +19,7 @@ */ package com.cloud.network; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; @@ -264,4 +265,8 @@ public interface NetworkManager extends NetworkService { List listNetworkOfferingServices(long networkOfferingId); boolean areServicesEnabledInZone(long zoneId, long networkOfferingId, String tags, List services); + + public Map> getIpToServices(Network network, List publicIps, boolean rulesRevoked); + + public Map> getProviderToIpList(Network network, Map> ipToServices); } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 99eb3422abb..a787e95ff35 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -126,10 +126,12 @@ import com.cloud.network.dao.PhysicalNetworkTrafficTypeDao; import com.cloud.network.dao.PhysicalNetworkTrafficTypeVO; import com.cloud.network.element.DhcpServiceProvider; import com.cloud.network.element.FirewallServiceProvider; +import com.cloud.network.element.IpDeployer; import com.cloud.network.element.LoadBalancingServiceProvider; import com.cloud.network.element.NetworkElement; import com.cloud.network.element.PortForwardingServiceProvider; import com.cloud.network.element.RemoteAccessVPNServiceProvider; +import com.cloud.network.element.SourceNatServiceProvider; import com.cloud.network.element.StaticNatServiceProvider; import com.cloud.network.element.UserDataServiceProvider; import com.cloud.network.element.VirtualRouterElement; @@ -310,7 +312,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag private static HashMap> s_serviceToImplementedProvidersMap = new HashMap>(); private static HashMap s_providerToNetworkElementMap = new HashMap(); - private NetworkElement getElementImplementingProvider(String providerName){ + public NetworkElement getElementImplementingProvider(String providerName){ String elementName = s_providerToNetworkElementMap.get(providerName); NetworkElement element = _networkElements.get(elementName); return element; @@ -603,104 +605,218 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag return success; } - protected boolean applyIpAssociations(Network network, boolean rulesRevoked, boolean continueOnError, List publicIps) throws ResourceUnavailableException { - boolean success = true; - List firewallPublicIps = new ArrayList(); - List loadbalncerPublicIps = new ArrayList(); + private Map> getProviderServiceMap(long networkId) { + Map> map = new HashMap>(); + List nsms = _ntwkSrvcDao.getServicesInNetwork(networkId); + for (NetworkServiceMapVO nsm : nsms) { + Set services = map.get(Provider.getProvider(nsm.getProvider())); + if (services == null) { + services = new HashSet(); + } + services.add(Service.getService(nsm.getService())); + map.put(Provider.getProvider(nsm.getProvider()), services); + } + return map; + } + + private Map> getServiceProviderMap(long networkId) { + Map> map = new HashMap>(); + List nsms = _ntwkSrvcDao.getServicesInNetwork(networkId); + for (NetworkServiceMapVO nsm : nsms) { + Set providers = map.get(Service.getService(nsm.getService())); + if (providers == null) { + providers = new HashSet(); + } + providers.add(Provider.getProvider(nsm.getProvider())); + map.put(Service.getService(nsm.getService()), providers); + } + return map; + } + + /* Get a list of IPs, classify them by service */ + @Override + public Map> getIpToServices(Network network, List publicIps, boolean rulesRevoked) { + Map> ipToServices = new HashMap>(); if (publicIps != null && !publicIps.isEmpty()) { + boolean gotSNAT = false; for (PublicIp ip : publicIps) { + Set services = ipToServices.get(ip); + if (services == null) { + services = new HashSet(); + } if (ip.isSourceNat()) { - // Source nat ip address should always be sent first - firewallPublicIps.add(0, ip); - } else if (ip.isOneToOneNat()) { - firewallPublicIps.add(ip); - } else { - //if IP in allocating state then it will not have any rules attached so skip IPAssoc to network service provider - if (ip.getState() == State.Allocating) { - continue; - } - - // check if any active rules are applied on the public IP - Purpose purpose = getPublicIpPurpose(ip, false); - if (purpose == null) { - // since no active rules are there check if any rules are applied on the public IP but are in revoking state - purpose = getPublicIpPurpose(ip, true); - if (purpose == null) { - // IP is not being used for any purpose so skip IPAssoc to network service provider - continue; - } else { - if (rulesRevoked) { - // no active rules/revoked rules are associated with this public IP, so remove the association with the provider - ip.setState(State.Releasing); - } else { - if (ip.getState() == State.Releasing) { - // rules are not revoked yet, so don't let the network service provider revoke the IP association - // mark IP is allocated so that IP association will not be removed from the provider - ip.setState(State.Allocated); - } - } - } + if (!gotSNAT) { + services.add(Service.SourceNat); + gotSNAT = true; + } else { + //TODO throw proper exception + throw new CloudRuntimeException("Multiply generic source NAT IPs in network " + network.getId() + "!"); } + } + ipToServices.put(ip, services); + + //if IP in allocating state then it will not have any rules attached so skip IPAssoc to network service provider + if (ip.getState() == State.Allocating) { + continue; + } - switch(purpose) { - case LoadBalancing: - loadbalncerPublicIps.add(ip); - break; - - case PortForwarding: - case StaticNat: - case Firewall: - firewallPublicIps.add(ip); - break; - default: + // check if any active rules are applied on the public IP + Set purposes = getPublicIpPurposeInRules(ip, false); + if (purposes == null || purposes.isEmpty()) { + // since no active rules are there check if any rules are applied on the public IP but are in revoking state + purposes = getPublicIpPurposeInRules(ip, true); + if (purposes == null || purposes.isEmpty()) { + // IP is not being used for any purpose so skip IPAssoc to network service provider + continue; + } else { + if (rulesRevoked) { + // no active rules/revoked rules are associated with this public IP, so remove the association with the provider + ip.setState(State.Releasing); + } else { + if (ip.getState() == State.Releasing) { + // rules are not revoked yet, so don't let the network service provider revoke the IP association + // mark IP is allocated so that IP association will not be removed from the provider + ip.setState(State.Allocated); + } + } } } + if (purposes.contains(Purpose.StaticNat)) { + services.add(Service.StaticNat); + } + if (purposes.contains(Purpose.LoadBalancing)) { + services.add(Service.Lb); + } + if (purposes.contains(Purpose.PortForwarding)) { + services.add(Service.PortForwarding); + } + if (purposes.contains(Purpose.Vpn)) { + services.add(Service.Vpn); + } + if (services.isEmpty()) { + continue; + } + ipToServices.put(ip, services); + } + } + return ipToServices; + } + + public boolean canIpUsedForService(Network network, PublicIp ip, Service service) { + // We need to check if it's non-conserve mode, then the new ip should not be used by any other services + NetworkOffering offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); + if (offering.isConserveMode()) { + List ipList = new ArrayList(); + ipList.add(ip); + Map> ipToServices = getIpToServices(network, ipList, false); + Set currentServices = ipToServices.get(ip); + // Not used currently, safe + if (currentServices == null || currentServices.isEmpty()) { + return true; + } + } + Map> serviceToProviders = getServiceProviderMap(network.getId()); + Set currentProviders = serviceToProviders.get(service); + if (currentProviders.size() > 1) { + throw new CloudRuntimeException("Can't support multiply providers for same service now!"); + } + Provider currentProvider = (Provider)currentProviders.toArray()[0]; + + return true; + } + + /* Return a mapping between NetworkElement in the network and the IP they should applied */ + @Override + public Map> getProviderToIpList(Network network, Map> ipToServices) { + NetworkOffering offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); + if (!offering.isConserveMode()) { + for (PublicIp ip : ipToServices.keySet()) { + Set services = ipToServices.get(ip); + if (services != null && services.size() > 1) { + //TODO throw proper exception + throw new CloudRuntimeException(""); + } } } - - String lbProvider = _ntwkSrvcDao.getProviderForServiceInNetwork(network.getId(), Service.Lb); - String fwProvider = _ntwkSrvcDao.getProviderForServiceInNetwork(network.getId(), Service.Firewall); - - for (NetworkElement element : _networkElements) { - try { - if (element instanceof FirewallServiceProvider && element instanceof LoadBalancingServiceProvider) { - List allIps = new ArrayList(); - - if (lbProvider.equalsIgnoreCase(element.getProvider().getName()) && fwProvider.equalsIgnoreCase(element.getProvider().getName())) { - allIps.addAll(firewallPublicIps); - allIps.addAll(loadbalncerPublicIps); - } else if (fwProvider.equalsIgnoreCase(element.getProvider().getName())) { - allIps.addAll(firewallPublicIps); - } else if (lbProvider.equalsIgnoreCase(element.getProvider().getName())) { - allIps.addAll(loadbalncerPublicIps); - } else { - continue; - } - - FirewallServiceProvider fwElement = (FirewallServiceProvider)element; - fwElement.applyIps(network, allIps); - } else if (element instanceof FirewallServiceProvider) { - FirewallServiceProvider fwElement = (FirewallServiceProvider)element; - if (fwProvider.equalsIgnoreCase(element.getProvider().getName())) { - fwElement.applyIps(network, firewallPublicIps); - } - } else if (element instanceof LoadBalancingServiceProvider) { - LoadBalancingServiceProvider lbElement = (LoadBalancingServiceProvider) element; - if (lbProvider.equalsIgnoreCase(element.getProvider().getName())) { - if (loadbalncerPublicIps != null && !loadbalncerPublicIps.isEmpty()) { - lbElement.applyLoadBalancerIp(network, publicIps); - } - } - } else { + Map> serviceToIps = new HashMap>(); + for (PublicIp ip : ipToServices.keySet()) { + for (Service service : ipToServices.get(ip)) { + Set ips = serviceToIps.get(service); + if (ips == null) { + ips = new HashSet(); + } + ips.add(ip); + serviceToIps.put(service, ips); + } + } + //TODO Check different provider for same IP + Map> providerToServices = getProviderServiceMap(network.getId()); + Map> providerToIpList = new HashMap>(); + for (Provider provider: providerToServices.keySet()) { + Set services = providerToServices.get(provider); + //TODO add checking for services, multiply services may bind to one provider, which is invalid in non-conserved mode + ArrayList ipList = new ArrayList(); + Set ipSet = new HashSet(); + for (Service service: services) { + Set serviceIps = serviceToIps.get(service); + if (serviceIps == null || serviceIps.isEmpty()) { continue; } + ipSet.addAll(serviceIps); + } + Set sourceNatIps = serviceToIps.get(Service.SourceNat); + if (sourceNatIps != null && !sourceNatIps.isEmpty()) { + ipList.addAll(0, sourceNatIps); + ipSet.removeAll(sourceNatIps); + } + ipList.addAll(ipSet); + providerToIpList.put(provider, ipList); + } + return providerToIpList; + } + + protected boolean applyIpAssociations(Network network, boolean rulesRevoked, boolean continueOnError, List publicIps) throws ResourceUnavailableException { + boolean success = true; + + Map> ipToServices = getIpToServices(network, publicIps, rulesRevoked); + Map> providerToIpList = getProviderToIpList(network, ipToServices); + + for (Provider provider : providerToIpList.keySet()) { + try { + ArrayList ips = providerToIpList.get(provider); + if (ips == null || ips.isEmpty()) { + continue; + } + IpDeployer deployer = null; + NetworkElement element = getElementImplementingProvider(provider.getName()); + if (element instanceof SourceNatServiceProvider) { + deployer = ((SourceNatServiceProvider)element).getIpDeployer(network); + } else if (element instanceof StaticNatServiceProvider) { + deployer = ((StaticNatServiceProvider)element).getIpDeployer(network); + } else if (element instanceof LoadBalancingServiceProvider) { + deployer = ((LoadBalancingServiceProvider)element).getIpDeployer(network); + } else if (element instanceof PortForwardingServiceProvider) { + deployer = ((PortForwardingServiceProvider)element).getIpDeployer(network); + } else if (element instanceof RemoteAccessVPNServiceProvider) { + deployer = ((RemoteAccessVPNServiceProvider)element).getIpDeployer(network); + } else { + throw new CloudRuntimeException("Fail to get ip deployer for element: " + element); + } + Set services = new HashSet(); + for (PublicIp ip : ips) { + if (!ipToServices.containsKey(ip)) { + continue; + } + services.addAll(ipToServices.get(ip)); + } + deployer.applyIps(network, ips, services); } catch (ResourceUnavailableException e) { success = false; if (!continueOnError) { throw e; } else { - s_logger.debug("Resource is not available: " + element.getName(), e); + s_logger.debug("Resource is not available: " + provider.getName(), e); } } } @@ -708,51 +824,35 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag return success; } - Purpose getPublicIpPurpose(PublicIp ip, boolean includeRevoked) { + Set getPublicIpPurposeInRules(PublicIp ip, boolean includeRevoked) { + Set result = new HashSet(); if (includeRevoked) { - List loadBalancingRules = _firewallDao.listByIpAndPurpose(ip.getId(), Purpose.LoadBalancing); - if (loadBalancingRules != null && !loadBalancingRules.isEmpty()) { - return Purpose.LoadBalancing; + List rules = _firewallDao.listByIp(ip.getId()); + if (rules == null || rules.isEmpty()) { + return null; } - - List firewall_rules = _firewallDao.listByIpAndPurpose(ip.getId(), Purpose.Firewall); - if (firewall_rules != null && !firewall_rules.isEmpty()) { - return Purpose.Firewall; - } - - List staticNatRules = _firewallDao.listByIpAndPurpose(ip.getId(), Purpose.StaticNat); - if (staticNatRules != null && !staticNatRules.isEmpty()) { - return Purpose.StaticNat; - } - - List pfRules = _portForwardingDao.listByIp(ip.getId()); - if (pfRules != null && !pfRules.isEmpty()) { - return Purpose.PortForwarding; + + for (FirewallRuleVO rule : rules) { + // Firewall should attach to others, firewall rule alone make no sense + if (rule.getPurpose() != Purpose.Firewall) { + result.add(rule.getPurpose()); + } } } else { - List loadBalancingRules = _firewallDao.listByIpAndPurposeAndNotRevoked(ip.getId(), Purpose.LoadBalancing); - if (loadBalancingRules != null && !loadBalancingRules.isEmpty()) { - return Purpose.LoadBalancing; + List rules = _firewallDao.listByIpAndNotRevoked(ip.getId()); + if (rules == null || rules.isEmpty()) { + return null; } - - List firewall_rules = _firewallDao.listByIpAndPurposeAndNotRevoked(ip.getId(), Purpose.Firewall); - if (firewall_rules != null && !firewall_rules.isEmpty()) { - return Purpose.Firewall; - } - - List staticNatRules = _firewallDao.listByIpAndPurposeAndNotRevoked(ip.getId(), Purpose.StaticNat); - if (staticNatRules != null && !staticNatRules.isEmpty()) { - return Purpose.StaticNat; - } - - List pfRules = _portForwardingDao.listByIpAndNotRevoked(ip.getId()); - if (pfRules != null && !pfRules.isEmpty()) { - return Purpose.PortForwarding; + + for (FirewallRuleVO rule : rules) { + // Firewall is attached to others, firewall rule alone make no sense + if (rule.getPurpose() != Purpose.Firewall) { + result.add(rule.getPurpose()); + } } } - // we are here means, public IP has no active/revoked rules to know the purpose - return null; + return result; } @Override diff --git a/server/src/com/cloud/network/dao/FirewallRulesDao.java b/server/src/com/cloud/network/dao/FirewallRulesDao.java index cea32ea4887..001647bcab3 100644 --- a/server/src/com/cloud/network/dao/FirewallRulesDao.java +++ b/server/src/com/cloud/network/dao/FirewallRulesDao.java @@ -50,4 +50,8 @@ public interface FirewallRulesDao extends GenericDao { FirewallRuleVO findByRelatedId(long ruleId); List listSystemRules(); + + List listByIp(long ipAddressId); + + List listByIpAndNotRevoked(long ipAddressId); } diff --git a/server/src/com/cloud/network/dao/FirewallRulesDaoImpl.java b/server/src/com/cloud/network/dao/FirewallRulesDaoImpl.java index 949f86d6ae2..e38e5a34699 100644 --- a/server/src/com/cloud/network/dao/FirewallRulesDaoImpl.java +++ b/server/src/com/cloud/network/dao/FirewallRulesDaoImpl.java @@ -241,5 +241,21 @@ public class FirewallRulesDaoImpl extends GenericDaoBase i return findOneBy(sc); } + + @Override + public List listByIp(long ipId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("ipId", ipId); + + return listBy(sc); + } + @Override + public List listByIpAndNotRevoked(long ipId) { + SearchCriteria sc = NotRevokedSearch.create(); + sc.setParameters("ipId", ipId); + sc.setParameters("state", State.Revoke); + + return listBy(sc); + } } diff --git a/server/src/com/cloud/network/element/ElasticLoadBalancerElement.java b/server/src/com/cloud/network/element/ElasticLoadBalancerElement.java index 3fc8f11bbb4..ba40ee73602 100644 --- a/server/src/com/cloud/network/element/ElasticLoadBalancerElement.java +++ b/server/src/com/cloud/network/element/ElasticLoadBalancerElement.java @@ -20,6 +20,7 @@ package com.cloud.network.element; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import javax.ejb.Local; import javax.naming.ConfigurationException; @@ -54,7 +55,7 @@ import com.cloud.vm.VirtualMachineProfile; @Local(value=NetworkElement.class) -public class ElasticLoadBalancerElement extends AdapterBase implements LoadBalancingServiceProvider { +public class ElasticLoadBalancerElement extends AdapterBase implements LoadBalancingServiceProvider, IpDeployer { private static final Logger s_logger = Logger.getLogger(ElasticLoadBalancerElement.class); private static final Map> capabilities = setCapabilities(); @Inject NetworkManager _networkManager; @@ -181,9 +182,14 @@ public class ElasticLoadBalancerElement extends AdapterBase implements LoadBalan return true; } - @Override - public boolean applyLoadBalancerIp(Network network, List ipAddress) throws ResourceUnavailableException { - // TODO Auto-generated method stub - return false; - } + @Override + public boolean applyIps(Network network, List ipAddress, Set services) throws ResourceUnavailableException { + // TODO Auto-generated method stub + return false; + } + + @Override + public IpDeployer getIpDeployer(Network network) { + return this; + } } diff --git a/server/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java b/server/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java index 68567f88dbc..be62b4dd246 100644 --- a/server/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java +++ b/server/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import javax.ejb.Local; @@ -88,7 +89,7 @@ import com.cloud.vm.VirtualMachineProfile; import com.google.gson.Gson; @Local(value=NetworkElement.class) -public class F5ExternalLoadBalancerElement extends ExternalLoadBalancerDeviceManagerImpl implements LoadBalancingServiceProvider, F5ExternalLoadBalancerElementService, ExternalLoadBalancerDeviceManager { +public class F5ExternalLoadBalancerElement extends ExternalLoadBalancerDeviceManagerImpl implements LoadBalancingServiceProvider, IpDeployer, F5ExternalLoadBalancerElementService, ExternalLoadBalancerDeviceManager { private static final Logger s_logger = Logger.getLogger(F5ExternalLoadBalancerElement.class); @@ -442,9 +443,14 @@ public class F5ExternalLoadBalancerElement extends ExternalLoadBalancerDeviceMan return true; } - @Override - public boolean applyLoadBalancerIp(Network network, List ipAddress) throws ResourceUnavailableException { + @Override + public boolean applyIps(Network network, List ipAddress, Set service) throws ResourceUnavailableException { // return true, as IP will be associated as part of LB rule configuration - return true; - } + return false; + } + + @Override + public IpDeployer getIpDeployer(Network network) { + return this; + } } diff --git a/server/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java b/server/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java index 17daa651b69..25da8ea2ba4 100644 --- a/server/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java +++ b/server/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java @@ -23,6 +23,8 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; + import javax.ejb.Local; import org.apache.log4j.Logger; @@ -87,7 +89,7 @@ import com.cloud.vm.VirtualMachineProfile; @Local(value=NetworkElement.class) public class JuniperSRXExternalFirewallElement extends ExternalFirewallDeviceManagerImpl implements SourceNatServiceProvider, FirewallServiceProvider, - PortForwardingServiceProvider, RemoteAccessVPNServiceProvider, JuniperSRXFirewallElementService{ + PortForwardingServiceProvider, RemoteAccessVPNServiceProvider, IpDeployer, JuniperSRXFirewallElementService{ private static final Logger s_logger = Logger.getLogger(JuniperSRXExternalFirewallElement.class); @@ -496,8 +498,13 @@ public class JuniperSRXExternalFirewallElement extends ExternalFirewallDeviceMan return true; } + @Override + public IpDeployer getIpDeployer(Network network) { + return this; + } + @Override - public boolean applyIps(Network network, List ipAddress) throws ResourceUnavailableException { + public boolean applyIps(Network network, List ipAddress, Set service) throws ResourceUnavailableException { // TODO Auto-generated method stub return false; } diff --git a/server/src/com/cloud/network/element/NetscalerExternalLoadBalancerElement.java b/server/src/com/cloud/network/element/NetscalerExternalLoadBalancerElement.java index a87e9a98327..87330cfc944 100644 --- a/server/src/com/cloud/network/element/NetscalerExternalLoadBalancerElement.java +++ b/server/src/com/cloud/network/element/NetscalerExternalLoadBalancerElement.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import javax.ejb.Local; @@ -88,7 +89,7 @@ import com.cloud.vm.VirtualMachineProfile; import com.google.gson.Gson; @Local(value=NetworkElement.class) -public class NetscalerExternalLoadBalancerElement extends ExternalLoadBalancerDeviceManagerImpl implements LoadBalancingServiceProvider, NetscalerLoadBalancerElementService, ExternalLoadBalancerDeviceManager { +public class NetscalerExternalLoadBalancerElement extends ExternalLoadBalancerDeviceManagerImpl implements LoadBalancingServiceProvider, NetscalerLoadBalancerElementService, ExternalLoadBalancerDeviceManager, IpDeployer { private static final Logger s_logger = Logger.getLogger(NetscalerExternalLoadBalancerElement.class); @@ -467,9 +468,14 @@ public class NetscalerExternalLoadBalancerElement extends ExternalLoadBalancerDe return true; } - @Override - public boolean applyLoadBalancerIp(Network network, List ipAddress) throws ResourceUnavailableException { + @Override + public boolean applyIps(Network network, List ipAddress, Set service) throws ResourceUnavailableException { // return true, as IP will be associated as part of LB rule configuration - return true; - } + return false; + } + + @Override + public IpDeployer getIpDeployer(Network network) { + return this; + } } \ No newline at end of file diff --git a/server/src/com/cloud/network/element/VirtualRouterElement.java b/server/src/com/cloud/network/element/VirtualRouterElement.java index 897b37fba57..b7e183f48a9 100644 --- a/server/src/com/cloud/network/element/VirtualRouterElement.java +++ b/server/src/com/cloud/network/element/VirtualRouterElement.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import javax.ejb.Local; @@ -84,9 +85,8 @@ import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.UserVmDao; import com.google.gson.Gson; - @Local(value=NetworkElement.class) -public class VirtualRouterElement extends AdapterBase implements VirtualRouterElementService, DhcpServiceProvider, UserDataServiceProvider, SourceNatServiceProvider, StaticNatServiceProvider, FirewallServiceProvider, LoadBalancingServiceProvider, PortForwardingServiceProvider, RemoteAccessVPNServiceProvider { +public class VirtualRouterElement extends AdapterBase implements VirtualRouterElementService, DhcpServiceProvider, UserDataServiceProvider, SourceNatServiceProvider, StaticNatServiceProvider, FirewallServiceProvider, LoadBalancingServiceProvider, PortForwardingServiceProvider, RemoteAccessVPNServiceProvider, IpDeployer { private static final Logger s_logger = Logger.getLogger(VirtualRouterElement.class); private static final Map> capabilities = setCapabilities(); @@ -256,8 +256,15 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl } @Override - public boolean applyIps(Network network, List ipAddress) throws ResourceUnavailableException { - if (canHandle(network, Service.Firewall)) { + public boolean applyIps(Network network, List ipAddress, Set services) throws ResourceUnavailableException { + boolean canHandle = true; + for (Service service : services) { + if (!canHandle(network, service)) { + canHandle = false; + break; + } + } + if (canHandle) { List routers = _routerDao.listByNetworkAndRole(network.getId(), Role.VIRTUAL_ROUTER); if (routers == null || routers.isEmpty()) { s_logger.debug("Virtual router elemnt doesn't need to associate ip addresses on the backend; virtual router doesn't exist in the network " + network.getId()); @@ -270,21 +277,6 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl } } - @Override - public boolean applyLoadBalancerIp(Network network, List ipAddress) throws ResourceUnavailableException { - if (canHandle(network, Service.Lb)) { - List routers = _routerDao.listByNetworkAndRole(network.getId(), Role.VIRTUAL_ROUTER); - if (routers == null || routers.isEmpty()) { - s_logger.debug("Virtual router element doesn't need to associate load balancer ip addresses on the backend; virtual router doesn't exist in the network " + network.getId()); - return true; - } - - return _routerMgr.associateIP(network, ipAddress, routers); - } else { - return false; - } - } - @Override public Provider getProvider() { return Provider.VirtualRouter; @@ -660,4 +652,8 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl return true; } + @Override + public IpDeployer getIpDeployer(Network network) { + return this; + } } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 42b5d9bca22..4bc68607eda 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -146,6 +146,7 @@ import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; import com.cloud.network.dao.RemoteAccessVpnDao; import com.cloud.network.dao.VirtualRouterProviderDao; import com.cloud.network.dao.VpnUserDao; +import com.cloud.network.element.NetworkElement; import com.cloud.network.lb.LoadBalancingRule; import com.cloud.network.lb.LoadBalancingRule.LbDestination; import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; @@ -1781,13 +1782,20 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian long zoneId = router.getDataCenterIdToDeployIn(); final List userIps = _networkMgr.listPublicIpAddressesInVirtualNetwork(ownerId, zoneId, null, null); - List publicIps = new ArrayList(); + List allPublicIps = new ArrayList(); if (userIps != null && !userIps.isEmpty()) { for (IPAddressVO userIp : userIps) { PublicIp publicIp = new PublicIp(userIp, _vlanDao.findById(userIp.getVlanId()), NetUtils.createSequenceBasedMacAddress(userIp.getMacAddress())); - publicIps.add(publicIp); + allPublicIps.add(publicIp); } } + + //Get public Ips that should be handled by router + Network network = _networkDao.findById(networkId); + Map> ipToServices = _networkMgr.getIpToServices(network, allPublicIps, false); + Map> providerToIpList = _networkMgr.getProviderToIpList(network, ipToServices); + // Only cover virtual router for now, if ELB use it this need to be modified + ArrayList publicIps = providerToIpList.get(Provider.VirtualRouter); s_logger.debug("Found " + publicIps.size() + " ip(s) to apply as a part of domR " + router + " start."); @@ -1799,8 +1807,13 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian List staticNats = new ArrayList(); List firewallRules = new ArrayList(); + // Re-apply public ip addresses - should come before PF/LB/VPN + if (_networkMgr.isProviderSupportServiceInNetwork(router.getNetworkId(), Service.Firewall, provider)) { + createAssociateIPCommands(router, publicIps, cmds, 0); + } + //Get information about all the rules (StaticNats and StaticNatRules; PFVPN to reapply on domR start) - for (PublicIpAddress ip : publicIps) { + for (PublicIp ip : publicIps) { if (_networkMgr.isProviderSupportServiceInNetwork(router.getNetworkId(), Service.PortForwarding, provider)) { pfRules.addAll(_pfRulesDao.listForApplication(ip.getId())); }