From 717f9dcd4d25e2a3ccf12598d16cc5d81fd880a9 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Fri, 4 Jan 2013 18:56:47 -0800 Subject: [PATCH 1/5] CLOUDSTACK-306: Implement SRX firewall Use SRX firewall filter as SRX firewall. The old security policy mechanism cannot be used as IP based. This would enable SRX's ability to control traffic for F5 behind it. --- .../cloud/agent/api/to/FirewallRuleTO.java | 1 + .../cloud/agent/api/to/StaticNatRuleTO.java | 5 + .../JuniperSRXExternalFirewallElement.java | 2 +- .../network/resource/JuniperSrxResource.java | 239 +++++++++++++++++- .../juniper/firewall-filter-term-add.xml | 25 ++ .../juniper/firewall-filter-term-getone.xml | 14 + scripts/network/juniper/template-entry.xml | 3 + .../ExternalFirewallDeviceManager.java | 9 + .../ExternalFirewallDeviceManagerImpl.java | 189 +++++++++++--- 9 files changed, 445 insertions(+), 42 deletions(-) create mode 100644 scripts/network/juniper/firewall-filter-term-add.xml create mode 100644 scripts/network/juniper/firewall-filter-term-getone.xml create mode 100644 scripts/network/juniper/template-entry.xml diff --git a/api/src/com/cloud/agent/api/to/FirewallRuleTO.java b/api/src/com/cloud/agent/api/to/FirewallRuleTO.java index 01860204c00..8ce3def11d6 100644 --- a/api/src/com/cloud/agent/api/to/FirewallRuleTO.java +++ b/api/src/com/cloud/agent/api/to/FirewallRuleTO.java @@ -58,6 +58,7 @@ public class FirewallRuleTO { this(id,null,srcIp,protocol,srcPortStart,srcPortEnd,revoked,alreadyAdded,purpose,sourceCidr,icmpType,icmpCode); } public FirewallRuleTO(long id,String srcVlanTag, String srcIp, String protocol, Integer srcPortStart, Integer srcPortEnd, boolean revoked, boolean alreadyAdded, FirewallRule.Purpose purpose, List sourceCidr,Integer icmpType,Integer icmpCode) { + this.id = id; this.srcVlanTag = srcVlanTag; this.srcIp = srcIp; this.protocol = protocol; diff --git a/api/src/com/cloud/agent/api/to/StaticNatRuleTO.java b/api/src/com/cloud/agent/api/to/StaticNatRuleTO.java index fd77dd69578..6f600149237 100644 --- a/api/src/com/cloud/agent/api/to/StaticNatRuleTO.java +++ b/api/src/com/cloud/agent/api/to/StaticNatRuleTO.java @@ -47,6 +47,11 @@ public class StaticNatRuleTO extends FirewallRuleTO{ super(id, srcIp, protocol, srcPortStart, srcPortEnd, revoked, alreadyAdded, FirewallRule.Purpose.StaticNat, null,0,0); this.dstIp = dstIp; } + + public StaticNatRuleTO(long id,String srcVlanTag, String srcIp, Integer srcPortStart, Integer srcPortEnd, String dstIp, Integer dstPortStart, Integer dstPortEnd, String protocol, boolean revoked, boolean alreadyAdded) { + super(id, srcVlanTag, srcIp, protocol, srcPortStart, srcPortEnd, revoked, alreadyAdded, FirewallRule.Purpose.StaticNat, null,0,0); + this.dstIp = dstIp; + } public String getDstIp() { return dstIp; diff --git a/plugins/network-elements/juniper-srx/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java b/plugins/network-elements/juniper-srx/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java index 95bc031726a..50c088c2447 100644 --- a/plugins/network-elements/juniper-srx/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java +++ b/plugins/network-elements/juniper-srx/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java @@ -268,7 +268,7 @@ public class JuniperSRXExternalFirewallElement extends ExternalFirewallDeviceMan // Set capabilities for Firewall service Map firewallCapabilities = new HashMap(); - firewallCapabilities.put(Capability.SupportedProtocols, "tcp,udp"); + firewallCapabilities.put(Capability.SupportedProtocols, "tcp,udp,icmp"); firewallCapabilities.put(Capability.MultipleIps, "true"); firewallCapabilities.put(Capability.TrafficStatistics, "per public ip"); capabilities.put(Service.Firewall, firewallCapabilities); diff --git a/plugins/network-elements/juniper-srx/src/com/cloud/network/resource/JuniperSrxResource.java b/plugins/network-elements/juniper-srx/src/com/cloud/network/resource/JuniperSrxResource.java index ebb3de6c850..f823ab8af4f 100644 --- a/plugins/network-elements/juniper-srx/src/com/cloud/network/resource/JuniperSrxResource.java +++ b/plugins/network-elements/juniper-srx/src/com/cloud/network/resource/JuniperSrxResource.java @@ -55,6 +55,7 @@ import com.cloud.agent.api.routing.IpAssocAnswer; import com.cloud.agent.api.routing.IpAssocCommand; import com.cloud.agent.api.routing.NetworkElementCommand; import com.cloud.agent.api.routing.RemoteAccessVpnCfgCommand; +import com.cloud.agent.api.routing.SetFirewallRulesCommand; import com.cloud.agent.api.routing.SetPortForwardingRulesCommand; import com.cloud.agent.api.routing.SetStaticNatRulesCommand; import com.cloud.agent.api.routing.VpnUsersCfgCommand; @@ -64,6 +65,7 @@ import com.cloud.agent.api.to.IpAddressTO; import com.cloud.agent.api.to.PortForwardingRuleTO; import com.cloud.agent.api.to.StaticNatRuleTO; import com.cloud.host.Host; +import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.resource.ServerResource; import com.cloud.utils.NumbersUtil; @@ -75,7 +77,6 @@ public class JuniperSrxResource implements ServerResource { private String _name; private String _zoneId; - private String _physicalNetworkId; private String _ip; private String _username; private String _password; @@ -89,6 +90,7 @@ public class JuniperSrxResource implements ServerResource { private Integer _timeoutInSeconds; private String _publicZone; private String _privateZone; + private String _publicZoneInputFilterName; private String _publicInterface; private String _usageInterface; private String _privateInterface; @@ -159,6 +161,9 @@ public class JuniperSrxResource implements ServerResource { ACCESS_PROFILE_ADD("access-profile-add.xml"), ACCESS_PROFILE_GETONE("access-profile-getone.xml"), ACCESS_PROFILE_GETALL("access-profile-getall.xml"), + FIREWALL_FILTER_TERM_ADD("firewall-filter-term-add.xml"), + FIREWALL_FILTER_TERM_GETONE("firewall-filter-term-getone.xml"), + TEMPLATE_ENTRY("template-entry.xml"), OPEN_CONFIGURATION("open-configuration.xml"), CLOSE_CONFIGURATION("close-configuration.xml"), COMMIT("commit.xml"), @@ -231,12 +236,74 @@ public class JuniperSrxResource implements ServerResource { } } + public class FirewallFilterTerm { + private String name; + private List sourceCidrs; + private String destIp; + private String portRange; + private String protocol; + private String icmpType; + private String icmpCode; + private String countName; + + private FirewallFilterTerm(String name, List sourceCidrs, String destIp, String protocol, Integer startPort, Integer endPort, + Integer icmpType, Integer icmpCode, String countName) { + this.name = name; + this.sourceCidrs = sourceCidrs; + this.destIp = destIp; + this.protocol = protocol; + + if (protocol.equals("tcp") || protocol.equals("udp")) { + this.portRange = String.valueOf(startPort) + "-" + String.valueOf(endPort); + } else if (protocol.equals("icmp")) { + this.icmpType = String.valueOf(icmpType); + this.icmpCode = String.valueOf(icmpCode); + } else { + assert protocol.equals("any"); + } + this.countName = countName; + + } + + public String getName() { + return name; + } + + public List getSourceCidrs() { + return sourceCidrs; + } + + public String getDestIp() { + return destIp; + } + + public String getPortRange() { + return portRange; + } + + public String getProtocol() { + return protocol; + } + + public String getIcmpType() { + return icmpType; + } + + public String getIcmpCode() { + return icmpCode; + } + + public String getCountName() { + return countName; + } + } + private enum SrxCommand { LOGIN, OPEN_CONFIGURATION, CLOSE_CONFIGURATION, COMMIT, ROLLBACK, CHECK_IF_EXISTS, CHECK_IF_IN_USE, ADD, DELETE, GET_ALL; } private enum Protocol { - tcp, udp, any; + tcp, udp, icmp, any; } private enum RuleMatchCondition { @@ -277,6 +344,8 @@ public class JuniperSrxResource implements ServerResource { return execute((SetStaticNatRulesCommand) cmd); } else if (cmd instanceof SetPortForwardingRulesCommand) { return execute((SetPortForwardingRulesCommand) cmd); + } else if (cmd instanceof SetFirewallRulesCommand) { + return execute((SetFirewallRulesCommand) cmd); } else if (cmd instanceof ExternalNetworkResourceUsageCommand) { return execute((ExternalNetworkResourceUsageCommand) cmd); } else if (cmd instanceof RemoteAccessVpnCfgCommand) { @@ -300,11 +369,6 @@ public class JuniperSrxResource implements ServerResource { throw new ConfigurationException("Unable to find zone"); } - _physicalNetworkId = (String) params.get("physicalNetworkId"); - if (_physicalNetworkId == null) { - throw new ConfigurationException("Unable to find physical network id in the configuration parameters"); - } - _ip = (String) params.get("ip"); if (_ip == null) { throw new ConfigurationException("Unable to find IP"); @@ -325,8 +389,6 @@ public class JuniperSrxResource implements ServerResource { throw new ConfigurationException("Unable to find public interface."); } - _usageInterface = (String) params.get("usageinterface"); - _privateInterface = (String) params.get("privateinterface"); if (_privateInterface == null) { throw new ConfigurationException("Unable to find private interface."); @@ -364,6 +426,8 @@ public class JuniperSrxResource implements ServerResource { throw new ConfigurationException("Unable to open a connection to the SRX."); } + _publicZoneInputFilterName = _publicZone; + _usageFilterVlanInput = new UsageFilter("vlan-input", null, "vlan-input"); _usageFilterVlanOutput = new UsageFilter("vlan-output", null, "vlan-output"); _usageFilterIPInput = new UsageFilter(_publicZone, "destination-address", "-i"); @@ -712,6 +776,50 @@ public class JuniperSrxResource implements ServerResource { s_logger.debug(msg); } + + /* security policies */ + private synchronized Answer execute(SetFirewallRulesCommand cmd) { + refreshSrxConnection(); + return execute(cmd, _numRetries); + } + + private Answer execute(SetFirewallRulesCommand cmd, int numRetries) { + FirewallRuleTO[] rules = cmd.getRules(); + try { + openConfiguration(); + + for (FirewallRuleTO rule : rules) { + int startPort = 0, endPort = 0; + if (rule.getSrcPortRange() != null) { + startPort = rule.getSrcPortRange()[0]; + endPort = rule.getSrcPortRange()[1]; + } + FirewallFilterTerm term = new FirewallFilterTerm(genIpIdentifier(rule.getSrcIp()) + "-" + String.valueOf(rule.getId()), rule.getSourceCidrList(), + rule.getSrcIp(), rule.getProtocol(), startPort, endPort, + rule.getIcmpType(), rule.getIcmpCode(), genIpIdentifier(rule.getSrcIp()) + _usageFilterIPInput.getCounterIdentifier()); + if (!rule.revoked()) { + manageFirewallFilter(SrxCommand.ADD, term, _publicZoneInputFilterName); + } else { + manageFirewallFilter(SrxCommand.DELETE, term, _publicZoneInputFilterName); + } + } + + commitConfiguration(); + return new Answer(cmd); + } catch (ExecutionException e) { + s_logger.error(e); + closeConfiguration(); + + if (numRetries > 0 && refreshSrxConnection()) { + int numRetriesRemaining = numRetries - 1; + s_logger.debug("Retrying SetFirewallRulesCommand. Number of retries remaining: " + numRetriesRemaining); + return execute(cmd, numRetriesRemaining); + } else { + return new Answer(cmd, e); + } + } + } + /* * Static NAT */ @@ -766,7 +874,6 @@ public class JuniperSrxResource implements ServerResource { private void addStaticNatRule(Long publicVlanTag, String publicIp, String privateIp, List rules) throws ExecutionException { manageProxyArp(SrxCommand.ADD, publicVlanTag, publicIp); manageStaticNatRule(SrxCommand.ADD, publicIp, privateIp); - manageUsageFilter(SrxCommand.ADD, _usageFilterIPInput, publicIp, null, genIpFilterTermName(publicIp)); manageAddressBookEntry(SrxCommand.ADD, _privateZone, privateIp, null); // Add a new security policy with the current set of applications @@ -778,7 +885,6 @@ public class JuniperSrxResource implements ServerResource { private void removeStaticNatRule(Long publicVlanTag, String publicIp, String privateIp) throws ExecutionException { manageStaticNatRule(SrxCommand.DELETE, publicIp, privateIp); manageProxyArp(SrxCommand.DELETE, publicVlanTag, publicIp); - manageUsageFilter(SrxCommand.DELETE, _usageFilterIPInput, publicIp, null, genIpFilterTermName(publicIp)); // Remove any existing security policy and clean up applications removeSecurityPolicyAndApplications(SecurityPolicyType.STATIC_NAT, privateIp); @@ -2781,6 +2887,108 @@ public class JuniperSrxResource implements ServerResource { } } + private String genNameValueEntry(String name, String value) { + String xml = SrxXml.TEMPLATE_ENTRY.getXml(); + xml = replaceXmlValue(xml, "name", name); + xml = replaceXmlValue(xml, "value", value); + return xml; + } + + private String genMultipleEntries(String name, List values) { + String result = ""; + for (String value : values) { + result = result + genNameValueEntry(name, value); + } + return result; + } + + private String genPortRangeEntry(String protocol, String portRange) { + String result = ""; + result = result + genNameValueEntry("protocol", protocol); + result = result + genNameValueEntry("destination-port", portRange); + return result; + } + + private String genIcmpEntries(String icmpType, String icmpCode) { + String result = ""; + result = result + genNameValueEntry("protocol", "icmp"); + if (icmpType.equals("-1")) { + result = result + genNameValueEntry("icmp-type", "0-255"); + } else { + result = result + genNameValueEntry("icmp-type", icmpType); + } + if (icmpCode.equals("-1")) { + result = result + genNameValueEntry("icmp-code", "0-255"); + } else { + result = result + genNameValueEntry("icmp-code", icmpCode); + } + return result; + } + + private boolean manageFirewallFilter(SrxCommand command, FirewallFilterTerm term, String filterName) throws ExecutionException { + String xml; + + switch(command) { + + case CHECK_IF_EXISTS: + xml = SrxXml.FIREWALL_FILTER_TERM_GETONE.getXml(); + xml = setDelete(xml, false); + xml = replaceXmlValue(xml, "filter-name", filterName); + xml = replaceXmlValue(xml, "term-name", term.getName()); + return sendRequestAndCheckResponse(command, xml, "name", term.getName()); + + case ADD: + if (manageFirewallFilter(SrxCommand.CHECK_IF_EXISTS, term, filterName)) { + return true; + } + + xml = SrxXml.FIREWALL_FILTER_TERM_ADD.getXml(); + + xml = replaceXmlValue(xml, "filter-name", filterName); + xml = replaceXmlValue(xml, "term-name", term.getName()); + xml = replaceXmlValue(xml, "source-address-entries", genMultipleEntries("source-address", term.getSourceCidrs())); + xml = replaceXmlValue(xml, "dest-ip-address", term.getDestIp()); + + String protocol = term.getProtocol(); + if (protocol.equals("tcp") || protocol.equals("udp")) { + xml = replaceXmlValue(xml, "protocol-options", genPortRangeEntry(protocol, term.getPortRange())); + } else if (protocol.equals("icmp")) { + xml = replaceXmlValue(xml, "protocol-options", genIcmpEntries(term.getIcmpType(), term.getIcmpCode())); + } else { + assert protocol.equals("any"); + xml = replaceXmlValue(xml, "protocol-options", ""); + } + xml = replaceXmlValue(xml, "count-name", term.getCountName()); + + if (!sendRequestAndCheckResponse(command, xml)) { + throw new ExecutionException("Failed to add firewall filter: " + term.getName()); + } else { + return true; + } + + case DELETE: + if (!manageFirewallFilter(SrxCommand.CHECK_IF_EXISTS, term, filterName)) { + return true; + } + + xml = SrxXml.FIREWALL_FILTER_TERM_GETONE.getXml(); + xml = setDelete(xml, true); + xml = replaceXmlValue(xml, "filter-name", filterName); + xml = replaceXmlValue(xml, "term-name", term.getName()); + + if (!sendRequestAndCheckResponse(command, xml)) { + throw new ExecutionException("Failed to delete firewall filter: " + term.getName()); + } else { + return true; + } + + default: + s_logger.debug("Unrecognized command."); + return false; + + } + } + /* * Usage */ @@ -2913,6 +3121,10 @@ public class JuniperSrxResource implements ServerResource { } UsageFilter filter = getUsageFilter(counterName); + if (filter == null) { + s_logger.debug("Failed to parse counter name in usage answer: " + counterName); + return; + } String usageAnswerKey = getUsageAnswerKey(filter, counterName); Map bytesMap = getBytesMap(answer, filter, usageAnswerKey); updateBytesMap(bytesMap, filter, usageAnswerKey, byteCount); @@ -2981,6 +3193,11 @@ public class JuniperSrxResource implements ServerResource { } private boolean checkResponse(String xmlResponse, boolean errorKeyAndValue, String key, String value) { + if (xmlResponse == null) { + s_logger.error("Failed to communicate with SRX!"); + return false; + } + if (!xmlResponse.contains("authentication-response")) { s_logger.debug("Checking response: " + xmlResponse); } else { diff --git a/scripts/network/juniper/firewall-filter-term-add.xml b/scripts/network/juniper/firewall-filter-term-add.xml new file mode 100644 index 00000000000..4f96ed4d16e --- /dev/null +++ b/scripts/network/juniper/firewall-filter-term-add.xml @@ -0,0 +1,25 @@ + + + + + +%filter-name% + +%term-name% + +%source-address-entries% + +%dest-ip-address% + +%protocol-options% + + +%count-name% + + + + + + + + diff --git a/scripts/network/juniper/firewall-filter-term-getone.xml b/scripts/network/juniper/firewall-filter-term-getone.xml new file mode 100644 index 00000000000..782290992c1 --- /dev/null +++ b/scripts/network/juniper/firewall-filter-term-getone.xml @@ -0,0 +1,14 @@ + + + + + +%filter-name% + +%term-name% + + + + + + diff --git a/scripts/network/juniper/template-entry.xml b/scripts/network/juniper/template-entry.xml new file mode 100644 index 00000000000..cf0cb6c37e3 --- /dev/null +++ b/scripts/network/juniper/template-entry.xml @@ -0,0 +1,3 @@ +<%name%> +%value% + diff --git a/server/src/com/cloud/network/ExternalFirewallDeviceManager.java b/server/src/com/cloud/network/ExternalFirewallDeviceManager.java index f6a39d96cea..f758ca1d341 100644 --- a/server/src/com/cloud/network/ExternalFirewallDeviceManager.java +++ b/server/src/com/cloud/network/ExternalFirewallDeviceManager.java @@ -22,6 +22,7 @@ import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.host.Host; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.PortForwardingRule; import com.cloud.resource.ServerResource; import com.cloud.utils.component.Manager; @@ -94,4 +95,12 @@ public interface ExternalFirewallDeviceManager extends Manager { */ public boolean manageGuestNetworkWithExternalFirewall(boolean add, Network guestConfig) throws ResourceUnavailableException, InsufficientCapacityException; + /** + * applies port forwarding rules + * @param network guest network if + * @param rules load balancer rules + * @return true if successfully applied rules + * @throws ResourceUnavailableException + */ + public boolean applyPortForwardingRules(Network network, List rules) throws ResourceUnavailableException; } diff --git a/server/src/com/cloud/network/ExternalFirewallDeviceManagerImpl.java b/server/src/com/cloud/network/ExternalFirewallDeviceManagerImpl.java index 1629dd5e5f3..4b67840db3a 100644 --- a/server/src/com/cloud/network/ExternalFirewallDeviceManagerImpl.java +++ b/server/src/com/cloud/network/ExternalFirewallDeviceManagerImpl.java @@ -34,9 +34,11 @@ import com.cloud.agent.api.StartupExternalLoadBalancerCommand; import com.cloud.agent.api.routing.IpAssocCommand; import com.cloud.agent.api.routing.NetworkElementCommand; import com.cloud.agent.api.routing.RemoteAccessVpnCfgCommand; +import com.cloud.agent.api.routing.SetFirewallRulesCommand; import com.cloud.agent.api.routing.SetPortForwardingRulesCommand; import com.cloud.agent.api.routing.SetStaticNatRulesCommand; import com.cloud.agent.api.routing.VpnUsersCfgCommand; +import com.cloud.agent.api.to.FirewallRuleTO; import com.cloud.agent.api.to.IpAddressTO; import com.cloud.agent.api.to.PortForwardingRuleTO; import com.cloud.agent.api.to.StaticNatRuleTO; @@ -65,6 +67,7 @@ import com.cloud.network.Network.Capability; import com.cloud.network.Network.Service; import com.cloud.network.Networks.TrafficType; import com.cloud.network.dao.ExternalFirewallDeviceDao; +import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.InlineLoadBalancerNicMapDao; import com.cloud.network.dao.LoadBalancerDao; @@ -78,14 +81,17 @@ import com.cloud.network.dao.VpnUserDao; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.PortForwardingRule; +import com.cloud.network.rules.StaticNat; import com.cloud.network.rules.StaticNatRule; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.resource.ResourceManager; +import com.cloud.resource.ResourceState; import com.cloud.resource.ResourceStateAdapter; import com.cloud.resource.ServerResource; import com.cloud.resource.UnableDeleteHostException; +import com.cloud.resource.ResourceStateAdapter.DeleteHostAnswer; import com.cloud.server.api.response.ExternalFirewallResponse; import com.cloud.user.Account; import com.cloud.user.AccountManager; @@ -98,6 +104,7 @@ import com.cloud.utils.db.DB; import com.cloud.utils.db.GlobalLock; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.Ip; import com.cloud.utils.net.NetUtils; import com.cloud.utils.net.UrlUtil; import com.cloud.vm.Nic.ReservationStrategy; @@ -133,6 +140,7 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl @Inject NetworkExternalFirewallDao _networkExternalFirewallDao; @Inject VpnUserDao _vpnUsersDao; @Inject HostDetailsDao _hostDetailDao; + @Inject FirewallRulesDao _fwRulesDao; private static final org.apache.log4j.Logger s_logger = Logger.getLogger(ExternalFirewallDeviceManagerImpl.class); private long _defaultFwCapacity; @@ -236,14 +244,26 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl throw new InvalidParameterValueException("Could not find an external firewall with ID: " + hostId); } + DetailVO fwHostDetails = _hostDetailDao.findDetail(hostId, ApiConstants.FIREWALL_DEVICE_ID); + long fwDeviceId = Long.parseLong(fwHostDetails.getValue()); + + // check if any networks are using this balancer device + List networks = _networkExternalFirewallDao.listByFirewallDeviceId(fwDeviceId); + if ((networks != null) && !networks.isEmpty()) { + throw new CloudRuntimeException("Delete can not be done as there are networks using the firewall device "); + } + try { - if (_resourceMgr.maintain(hostId) && _resourceMgr.deleteHost(hostId, false, false)) { - return true; - } else { - return false; - } - } catch (AgentUnavailableException e) { - s_logger.debug(e); + // put the host in maintenance state in order for it to be deleted + externalFirewall.setResourceState(ResourceState.Maintenance); + _hostDao.update(hostId, externalFirewall); + _resourceMgr.deleteHost(hostId, false, false); + + // delete the external load balancer entry + _externalFirewallDeviceDao.remove(fwDeviceId); + return true; + } catch (Exception e) { + s_logger.debug("Failed to delete external firewall device due to " + e.getMessage()); return false; } } @@ -316,6 +336,32 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl " to implement the network", DataCenter.class, network.getDataCenterId()); } + @DB + protected boolean freeFirewallForNetwork(Network network) { + Transaction txn = Transaction.currentTxn(); + GlobalLock deviceMapLock = GlobalLock.getInternLock("NetworkFirewallDeviceMap"); + try { + if (deviceMapLock.lock(120)) { + try { + NetworkExternalFirewallVO fwDeviceForNetwork = _networkExternalFirewallDao.findByNetworkId(network.getId()); + if (fwDeviceForNetwork != null) { + _networkExternalFirewallDao.remove(fwDeviceForNetwork.getId()); + } + } catch (Exception exception) { + txn.rollback(); + s_logger.error("Failed to release firewall device for the network" + network.getId() + " due to " + exception.getMessage()); + return false; + } finally { + deviceMapLock.unlock(); + } + } + } finally { + deviceMapLock.releaseRef(); + } + txn.commit(); + return true; + } + public String getExternalNetworkResourceGuid(long physicalNetworkId, String deviceName, String ip) { return physicalNetworkId + "-" + deviceName + "-" + ip; } @@ -422,15 +468,21 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl cmd.setAccessDetail(NetworkElementCommand.GUEST_VLAN_TAG, String.valueOf(guestVlanTag)); Answer answer = _agentMgr.easySend(externalFirewall.getId(), cmd); + List reservedIpAddressesForGuestNetwork = _nicDao.listIpAddressInNetwork(network.getId()); + if (answer == null || !answer.getResult()) { String action = add ? "implement" : "shutdown"; String answerDetails = (answer != null) ? answer.getDetails() : "answer was null"; String msg = "External firewall was unable to " + action + " the guest network on the external firewall in zone " + zone.getName() + " due to " + answerDetails; s_logger.error(msg); + if (!add && (!reservedIpAddressesForGuestNetwork.contains(network.getGateway()))) { + // If we failed the implementation as well, then just return, no complain + s_logger.error("Skip the shutdown of guest network on SRX because it seems we didn't implement it as well"); + return true; + } throw new ResourceUnavailableException(msg, DataCenter.class, zoneId); } - List reservedIpAddressesForGuestNetwork = _nicDao.listIpAddressInNetwork(network.getId()); if (add && (!reservedIpAddressesForGuestNetwork.contains(network.getGateway()))) { // Insert a new NIC for this guest network to reserve the gateway address savePlaceholderNic(network, network.getGateway()); @@ -447,6 +499,19 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl } } + // on network shutdown, delete placeHolder nics used for the firewall device + if (!add) { + List guestIps = _nicDao.listByNetworkId(network.getId()); + for (NicVO guestIp : guestIps) { + // only external firewall and external load balancer will create NicVO with PlaceHolder reservation strategy + if (guestIp.getReservationStrategy().equals(ReservationStrategy.PlaceHolder) && guestIp.getIp4Address().equals(network.getGateway())) { + _nicDao.remove(guestIp.getId()); + } + } + + freeFirewallForNetwork(network); + } + String action = add ? "implemented" : "shut down"; s_logger.debug("External firewall has " + action + " the guest network for account " + account.getAccountName() + "(id = " + account.getAccountId() + ") with VLAN tag " + guestVlanTag); @@ -456,6 +521,37 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl @Override public boolean applyFirewallRules(Network network, List rules) throws ResourceUnavailableException { // Find the external firewall in this zone + long zoneId = network.getDataCenterId(); + DataCenterVO zone = _dcDao.findById(zoneId); + ExternalFirewallDeviceVO fwDeviceVO = getExternalFirewallForNetwork(network); + // During destroy, device reference may already been clean up, then we just return true + if (fwDeviceVO == null) { + return true; + } + HostVO externalFirewall = _hostDao.findById(fwDeviceVO.getHostId()); + + assert(externalFirewall != null); + + if (network.getState() == Network.State.Allocated) { + s_logger.debug("External firewall was asked to apply firewall rules for network with ID " + network.getId() + "; this network is not implemented. Skipping backend commands."); + return true; + } + + List rulesTO = new ArrayList(); + + for (FirewallRule rule : rules) { + IpAddress sourceIp = _networkMgr.getIp(rule.getSourceIpAddressId()); + FirewallRuleTO ruleTO = new FirewallRuleTO(rule, null, sourceIp.getAddress().addr()); + rulesTO.add(ruleTO); + } + + //Firewall rules configured for staticNAT/PF + sendFirewallRules(rulesTO, zone, externalFirewall.getId()); + + return true; + } + + public boolean applyStaticNatRules(Network network, List rules) throws ResourceUnavailableException { long zoneId = network.getDataCenterId(); DataCenterVO zone = _dcDao.findById(zoneId); ExternalFirewallDeviceVO fwDeviceVO = getExternalFirewallForNetwork(network); @@ -469,32 +565,34 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl } List staticNatRules = new ArrayList(); - List portForwardingRules = new ArrayList(); - - for (FirewallRule rule : rules) { + + for (StaticNat rule : rules) { IpAddress sourceIp = _networkMgr.getIp(rule.getSourceIpAddressId()); Vlan vlan = _vlanDao.findById(sourceIp.getVlanId()); - if (rule.getPurpose() == Purpose.StaticNat) { - StaticNatRule staticNatRule = (StaticNatRule) rule; - StaticNatRuleTO ruleTO = new StaticNatRuleTO(staticNatRule, vlan.getVlanTag(), sourceIp.getAddress().addr(), staticNatRule.getDestIpAddress()); - staticNatRules.add(ruleTO); - } else if (rule.getPurpose() == Purpose.PortForwarding) { - PortForwardingRuleTO ruleTO = new PortForwardingRuleTO((PortForwardingRule) rule, vlan.getVlanTag(), sourceIp.getAddress().addr()); - portForwardingRules.add(ruleTO); - } + StaticNatRuleTO ruleTO = new StaticNatRuleTO(0,vlan.getVlanTag(), sourceIp.getAddress().addr(), -1, -1, rule.getDestIpAddress(), -1, -1, "any", rule.isForRevoke(), false); + staticNatRules.add(ruleTO); } - - // Apply static nat rules - applyStaticNatRules(staticNatRules, zone, externalFirewall.getId()); - - // apply port forwarding rules - applyPortForwardingRules(portForwardingRules, zone, externalFirewall.getId()); - + + sendStaticNatRules(staticNatRules, zone, externalFirewall.getId()); + return true; } + + protected void sendFirewallRules(List firewallRules, DataCenter zone, long externalFirewallId) throws ResourceUnavailableException { + if (!firewallRules.isEmpty()) { + SetFirewallRulesCommand cmd = new SetFirewallRulesCommand(firewallRules); + Answer answer = _agentMgr.easySend(externalFirewallId, cmd); + if (answer == null || !answer.getResult()) { + String details = (answer != null) ? answer.getDetails() : "details unavailable"; + String msg = "External firewall was unable to apply static nat rules to the SRX appliance in zone " + zone.getName() + " due to: " + details + "."; + s_logger.error(msg); + throw new ResourceUnavailableException(msg, DataCenter.class, zone.getId()); + } + } + } - protected void applyStaticNatRules(List staticNatRules, DataCenter zone, long externalFirewallId) throws ResourceUnavailableException { + protected void sendStaticNatRules(List staticNatRules, DataCenter zone, long externalFirewallId) throws ResourceUnavailableException { if (!staticNatRules.isEmpty()) { SetStaticNatRulesCommand cmd = new SetStaticNatRulesCommand(staticNatRules, null); Answer answer = _agentMgr.easySend(externalFirewallId, cmd); @@ -507,7 +605,7 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl } } - protected void applyPortForwardingRules(List portForwardingRules, DataCenter zone, long externalFirewallId) throws ResourceUnavailableException { + protected void sendPortForwardingRules(List portForwardingRules, DataCenter zone, long externalFirewallId) throws ResourceUnavailableException { if (!portForwardingRules.isEmpty()) { SetPortForwardingRulesCommand cmd = new SetPortForwardingRulesCommand(portForwardingRules); Answer answer = _agentMgr.easySend(externalFirewallId, cmd); @@ -648,7 +746,38 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl @Override public DeleteHostAnswer deleteHost(HostVO host, boolean isForced, boolean isForceDeleteStorage) throws UnableDeleteHostException { - // TODO Auto-generated method stub - return null; + if (host.getType() != com.cloud.host.Host.Type.ExternalFirewall) { + return null; + } + return new DeleteHostAnswer(true); + } + + @Override + public boolean applyPortForwardingRules(Network network, List rules) throws ResourceUnavailableException { + // Find the external firewall in this zone + long zoneId = network.getDataCenterId(); + DataCenterVO zone = _dcDao.findById(zoneId); + ExternalFirewallDeviceVO fwDeviceVO = getExternalFirewallForNetwork(network); + HostVO externalFirewall = _hostDao.findById(fwDeviceVO.getHostId()); + + assert(externalFirewall != null); + + if (network.getState() == Network.State.Allocated) { + s_logger.debug("External firewall was asked to apply firewall rules for network with ID " + network.getId() + "; this network is not implemented. Skipping backend commands."); + return true; + } + + List pfRules = new ArrayList(); + + for (PortForwardingRule rule : rules) { + IpAddress sourceIp = _networkMgr.getIp(rule.getSourceIpAddressId()); + Vlan vlan = _vlanDao.findById(sourceIp.getVlanId()); + + PortForwardingRuleTO ruleTO = new PortForwardingRuleTO(rule, vlan.getVlanTag(), sourceIp.getAddress().addr()); + pfRules.add(ruleTO); + } + + sendPortForwardingRules(pfRules, zone, externalFirewall.getId()); + return true; } } From 177e157cbfa40af82de628cb00876678d7646d2d Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Fri, 4 Jan 2013 18:56:47 -0800 Subject: [PATCH 2/5] CLOUDSTACK-306: Move inline mode parameter from device to network offering One F5 device can be used as inline and side-by-side at the same time(for different networks). So we can define inline or not on network base. --- .../cloud/agent/api/to/LoadBalancerTO.java | 12 ++- api/src/com/cloud/network/Network.java | 1 + .../com/cloud/offering/NetworkOffering.java | 1 + .../lb/ElasticLoadBalancerManagerImpl.java | 2 +- .../api/response/F5LoadBalancerResponse.java | 7 -- .../F5ExternalLoadBalancerElement.java | 4 +- .../network/resource/F5BigIpResource.java | 87 +++++++++---------- .../NetscalerLoadBalancerResponse.java | 7 -- .../network/element/NetscalerElement.java | 25 +----- .../src/com/cloud/api/ApiResponseHelper.java | 5 ++ .../ConfigurationManagerImpl.java | 23 ++++- ...ExternalLoadBalancerDeviceManagerImpl.java | 17 ++-- .../network/ExternalLoadBalancerDeviceVO.java | 18 +--- .../src/com/cloud/network/NetworkManager.java | 1 + .../com/cloud/network/NetworkManagerImpl.java | 5 ++ .../VirtualNetworkApplianceManagerImpl.java | 4 +- .../cloud/offerings/NetworkOfferingVO.java | 11 ++- .../cloud/server/ConfigurationServerImpl.java | 2 +- .../cloud/network/MockNetworkManagerImpl.java | 6 ++ .../com/cloud/vpc/MockNetworkManagerImpl.java | 5 ++ setup/db/create-schema.sql | 2 +- setup/db/db/schema-40to410.sql | 3 + 22 files changed, 131 insertions(+), 117 deletions(-) diff --git a/api/src/com/cloud/agent/api/to/LoadBalancerTO.java b/api/src/com/cloud/agent/api/to/LoadBalancerTO.java index 2e19af05569..2d166ea1e1e 100644 --- a/api/src/com/cloud/agent/api/to/LoadBalancerTO.java +++ b/api/src/com/cloud/agent/api/to/LoadBalancerTO.java @@ -43,12 +43,13 @@ public class LoadBalancerTO { String algorithm; boolean revoked; boolean alreadyAdded; + boolean inline; DestinationTO[] destinations; private StickinessPolicyTO[] stickinessPolicies; private AutoScaleVmGroupTO autoScaleVmGroupTO; final static int MAX_STICKINESS_POLICIES = 1; - public LoadBalancerTO(String uuid, String srcIp, int srcPort, String protocol, String algorithm, boolean revoked, boolean alreadyAdded, List destinations) { + public LoadBalancerTO(String uuid, String srcIp, int srcPort, String protocol, String algorithm, boolean revoked, boolean alreadyAdded, boolean inline, List destinations) { if (destinations == null) { // for autoscaleconfig destinations will be null; destinations = new ArrayList(); } @@ -59,6 +60,7 @@ public class LoadBalancerTO { this.algorithm = algorithm; this.revoked = revoked; this.alreadyAdded = alreadyAdded; + this.inline = inline; this.destinations = new DestinationTO[destinations.size()]; this.stickinessPolicies = null; int i = 0; @@ -67,8 +69,8 @@ public class LoadBalancerTO { } } - public LoadBalancerTO(String id, String srcIp, int srcPort, String protocol, String algorithm, boolean revoked, boolean alreadyAdded, List arg_destinations, List stickinessPolicies) { - this(id, srcIp, srcPort, protocol, algorithm, revoked, alreadyAdded, arg_destinations); + public LoadBalancerTO(String id, String srcIp, int srcPort, String protocol, String algorithm, boolean revoked, boolean alreadyAdded, boolean inline, List arg_destinations, List stickinessPolicies) { + this(id, srcIp, srcPort, protocol, algorithm, revoked, alreadyAdded, inline, arg_destinations); this.stickinessPolicies = null; if (stickinessPolicies != null && stickinessPolicies.size() > 0) { this.stickinessPolicies = new StickinessPolicyTO[MAX_STICKINESS_POLICIES]; @@ -116,6 +118,10 @@ public class LoadBalancerTO { return alreadyAdded; } + public boolean isInline() { + return inline; + } + public StickinessPolicyTO[] getStickinessPolicies() { return stickinessPolicies; } diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java index 188ef92e57b..a6cbdd80f0e 100644 --- a/api/src/com/cloud/network/Network.java +++ b/api/src/com/cloud/network/Network.java @@ -171,6 +171,7 @@ public interface Network extends ControlledEntity { public static final Capability AssociatePublicIP = new Capability("AssociatePublicIP"); public static final Capability ElasticLb = new Capability("ElasticLb"); public static final Capability AutoScaleCounters = new Capability("AutoScaleCounters"); + public static final Capability InlineMode = new Capability("InlineMode"); private String name; diff --git a/api/src/com/cloud/offering/NetworkOffering.java b/api/src/com/cloud/offering/NetworkOffering.java index 29828ab6172..8de1d13e372 100644 --- a/api/src/com/cloud/offering/NetworkOffering.java +++ b/api/src/com/cloud/offering/NetworkOffering.java @@ -111,4 +111,5 @@ public interface NetworkOffering { boolean getSpecifyIpRanges(); + boolean isInline(); } diff --git a/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java b/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java index 366070af21f..0043cac778a 100644 --- a/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java +++ b/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java @@ -296,7 +296,7 @@ ElasticLoadBalancerManager, Manager, VirtualMachineGuru { int srcPort = rule.getSourcePortStart(); String uuid = rule.getUuid(); List destinations = rule.getDestinations(); - LoadBalancerTO lb = new LoadBalancerTO(uuid, elbIp, srcPort, protocol, algorithm, revoked, false, destinations); + LoadBalancerTO lb = new LoadBalancerTO(uuid, elbIp, srcPort, protocol, algorithm, revoked, false, false, destinations); lbs[i++] = lb; } diff --git a/plugins/network-elements/f5/src/com/cloud/api/response/F5LoadBalancerResponse.java b/plugins/network-elements/f5/src/com/cloud/api/response/F5LoadBalancerResponse.java index dbb962fff03..275fca687ba 100644 --- a/plugins/network-elements/f5/src/com/cloud/api/response/F5LoadBalancerResponse.java +++ b/plugins/network-elements/f5/src/com/cloud/api/response/F5LoadBalancerResponse.java @@ -43,9 +43,6 @@ public class F5LoadBalancerResponse extends BaseResponse { @SerializedName(ApiConstants.LOAD_BALANCER_DEVICE_DEDICATED) @Param(description="true if device is dedicated for an account") private Boolean dedicatedLoadBalancer; - @SerializedName(ApiConstants.INLINE) @Param(description="true if device is inline with firewall device") - private Boolean inlineLoadBalancer; - @SerializedName(ApiConstants.PUBLIC_INTERFACE) @Param(description="the public interface of the load balancer") private String publicInterface; @@ -83,10 +80,6 @@ public class F5LoadBalancerResponse extends BaseResponse { this.dedicatedLoadBalancer = isDedicated; } - public void setInlineMode(boolean inline) { - this.inlineLoadBalancer = inline; - } - public void setPublicInterface(String publicInterface) { this.publicInterface = publicInterface; } diff --git a/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java b/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java index 579a4628c74..63e82751b4d 100644 --- a/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java +++ b/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java @@ -206,6 +206,9 @@ public class F5ExternalLoadBalancerElement extends ExternalLoadBalancerDeviceMan // Specifies that load balancing rules can only be made with public IPs that aren't source NAT IPs lbCapabilities.put(Capability.LoadBalancingSupportedIps, "additional"); + // Support inline mode with firewall + lbCapabilities.put(Capability.InlineMode, "true"); + LbStickinessMethod method; List methodList = new ArrayList(); method = new LbStickinessMethod(StickinessMethodType.LBCookieBased, "This is cookie based sticky method, can be used only for http"); @@ -448,7 +451,6 @@ public class F5ExternalLoadBalancerElement extends ExternalLoadBalancerDeviceMan } else { response.setDeviceCapacity(lbDeviceVO.getCapacity()); } - response.setInlineMode(lbDeviceVO.getIsInLineMode()); response.setDedicatedLoadBalancer(lbDeviceVO.getIsDedicatedDevice()); response.setProvider(lbDeviceVO.getProviderName()); response.setDeviceState(lbDeviceVO.getState().name()); diff --git a/plugins/network-elements/f5/src/com/cloud/network/resource/F5BigIpResource.java b/plugins/network-elements/f5/src/com/cloud/network/resource/F5BigIpResource.java index a45dd92ca98..618cd912e91 100644 --- a/plugins/network-elements/f5/src/com/cloud/network/resource/F5BigIpResource.java +++ b/plugins/network-elements/f5/src/com/cloud/network/resource/F5BigIpResource.java @@ -119,7 +119,6 @@ public class F5BigIpResource implements ServerResource { private String _privateInterface; private Integer _numRetries; private String _guid; - private boolean _inline; private Interfaces _interfaces; private LocalLBVirtualServerBindingStub _virtualServerApi; @@ -180,8 +179,6 @@ public class F5BigIpResource implements ServerResource { throw new ConfigurationException("Unable to find the guid"); } - _inline = Boolean.parseBoolean((String) params.get("inline")); - login(); return true; @@ -292,45 +289,49 @@ public class F5BigIpResource implements ServerResource { } private synchronized Answer execute(IpAssocCommand cmd, int numRetries) { - String[] results = new String[cmd.getIpAddresses().length]; - int i = 0; - try { - IpAddressTO[] ips = cmd.getIpAddresses(); - for (IpAddressTO ip : ips) { - long guestVlanTag = Long.valueOf(ip.getVlanId()); - String vlanSelfIp = _inline ? tagAddressWithRouteDomain(ip.getVlanGateway(), guestVlanTag) : ip.getVlanGateway(); - String vlanNetmask = ip.getVlanNetmask(); - - // Delete any existing guest VLAN with this tag, self IP, and netmask - deleteGuestVlan(guestVlanTag, vlanSelfIp, vlanNetmask); - - if (ip.isAdd()) { - // Add a new guest VLAN - addGuestVlan(guestVlanTag, vlanSelfIp, vlanNetmask); + String[] results = new String[cmd.getIpAddresses().length]; + int i = 0; + try { + IpAddressTO[] ips = cmd.getIpAddresses(); + for (IpAddressTO ip : ips) { + long guestVlanTag = Long.valueOf(ip.getVlanId()); + // It's a hack, using isOneToOneNat field for indicate if it's inline or not + // We'd better have an separate SetupGuestNetwork command later + boolean inline = ip.isOneToOneNat(); + String vlanSelfIp = inline ? tagAddressWithRouteDomain(ip.getVlanGateway(), guestVlanTag) : ip.getVlanGateway(); + String vlanNetmask = ip.getVlanNetmask(); + + // Delete any existing guest VLAN with this tag, self IP, and netmask + deleteGuestVlan(guestVlanTag, vlanSelfIp, vlanNetmask, inline); + + if (ip.isAdd()) { + // Add a new guest VLAN + addGuestVlan(guestVlanTag, vlanSelfIp, vlanNetmask, inline); + } + + saveConfiguration(); + results[i++] = ip.getPublicIp() + " - success"; } - - saveConfiguration(); - results[i++] = ip.getPublicIp() + " - success"; - } - - } catch (ExecutionException e) { - s_logger.error("Failed to execute IPAssocCommand due to " + e); - - if (shouldRetry(numRetries)) { - return retry(cmd, numRetries); - } else { - results[i++] = IpAssocAnswer.errorResult; - } - } - - return new IpAssocAnswer(cmd, results); - } + + } catch (ExecutionException e) { + s_logger.error("Failed to execute IPAssocCommand due to " + e); + + if (shouldRetry(numRetries)) { + return retry(cmd, numRetries); + } else { + results[i++] = IpAssocAnswer.errorResult; + } + } + + return new IpAssocAnswer(cmd, results); + } private synchronized Answer execute(LoadBalancerConfigCommand cmd, int numRetries) { try { long guestVlanTag = Long.parseLong(cmd.getAccessDetail(NetworkElementCommand.GUEST_VLAN_TAG)); LoadBalancerTO[] loadBalancers = cmd.getLoadBalancers(); for (LoadBalancerTO loadBalancer : loadBalancers) { + boolean inline = loadBalancer.isInline(); LbProtocol lbProtocol; try { if (loadBalancer.getProtocol() == null) { @@ -351,7 +352,7 @@ public class F5BigIpResource implements ServerResource { throw new ExecutionException("Got invalid algorithm: " + loadBalancer.getAlgorithm()); } - String srcIp = _inline ? tagAddressWithRouteDomain(loadBalancer.getSrcIp(), guestVlanTag) : loadBalancer.getSrcIp(); + String srcIp = inline ? tagAddressWithRouteDomain(loadBalancer.getSrcIp(), guestVlanTag) : loadBalancer.getSrcIp(); int srcPort = loadBalancer.getSrcPort(); String virtualServerName = genVirtualServerName(lbProtocol, srcIp, srcPort); @@ -371,7 +372,7 @@ public class F5BigIpResource implements ServerResource { List activePoolMembers = new ArrayList(); for (DestinationTO destination : loadBalancer.getDestinations()) { if (!destination.isRevoked()) { - String destIp = _inline ? tagAddressWithRouteDomain(destination.getDestIp(), guestVlanTag) : destination.getDestIp(); + String destIp = inline ? tagAddressWithRouteDomain(destination.getDestIp(), guestVlanTag) : destination.getDestIp(); addPoolMember(virtualServerName, destIp, destination.getDestPort()); activePoolMembers.add(destIp + "-" + destination.getDestPort()); } @@ -421,7 +422,7 @@ public class F5BigIpResource implements ServerResource { } } - private void addGuestVlan(long vlanTag, String vlanSelfIp, String vlanNetmask) throws ExecutionException { + private void addGuestVlan(long vlanTag, String vlanSelfIp, String vlanNetmask, boolean inline) throws ExecutionException { try { String vlanName = genVlanName(vlanTag); List allVlans = getVlans(); @@ -444,7 +445,7 @@ public class F5BigIpResource implements ServerResource { } } - if (_inline) { + if (inline) { List allRouteDomains = getRouteDomains(); if (!allRouteDomains.contains(vlanTag)) { long[] routeDomainIds = genLongArray(vlanTag); @@ -481,7 +482,7 @@ public class F5BigIpResource implements ServerResource { } - private void deleteGuestVlan(long vlanTag, String vlanSelfIp, String vlanNetmask) throws ExecutionException { + private void deleteGuestVlan(long vlanTag, String vlanSelfIp, String vlanNetmask, boolean inline) throws ExecutionException { try { // Delete all virtual servers and pools that use this guest VLAN deleteVirtualServersInGuestVlan(vlanSelfIp, vlanNetmask); @@ -496,7 +497,7 @@ public class F5BigIpResource implements ServerResource { } } - if (_inline) { + if (inline) { List allRouteDomains = getRouteDomains(); if (allRouteDomains.contains(vlanTag)) { s_logger.debug("Deleting route domain " + vlanTag); @@ -969,9 +970,7 @@ public class F5BigIpResource implements ServerResource { for (LocalLBVirtualServerVirtualServerStatisticEntry entry : stats.getStatistics()) { String virtualServerIp = entry.getVirtual_server().getAddress(); - if (_inline) { - virtualServerIp = stripRouteDomainFromAddress(virtualServerIp); - } + virtualServerIp = stripRouteDomainFromAddress(virtualServerIp); long[] bytesSentAndReceived = answer.ipBytes.get(virtualServerIp); diff --git a/plugins/network-elements/netscaler/src/com/cloud/api/response/NetscalerLoadBalancerResponse.java b/plugins/network-elements/netscaler/src/com/cloud/api/response/NetscalerLoadBalancerResponse.java index bbbfca515a1..7bc70dc786f 100644 --- a/plugins/network-elements/netscaler/src/com/cloud/api/response/NetscalerLoadBalancerResponse.java +++ b/plugins/network-elements/netscaler/src/com/cloud/api/response/NetscalerLoadBalancerResponse.java @@ -49,9 +49,6 @@ public class NetscalerLoadBalancerResponse extends BaseResponse { @SerializedName(ApiConstants.LOAD_BALANCER_DEVICE_DEDICATED) @Param(description="true if device is dedicated for an account") private Boolean dedicatedLoadBalancer; - @SerializedName(ApiConstants.INLINE) @Param(description="true if device is inline with firewall device") - private Boolean inlineLoadBalancer; - @SerializedName(ApiConstants.PUBLIC_INTERFACE) @Param(description="the public interface of the load balancer") private String publicInterface; @@ -94,10 +91,6 @@ public class NetscalerLoadBalancerResponse extends BaseResponse { this.deviceState = deviceState; } - public void setInlineMode(boolean inline) { - this.inlineLoadBalancer = inline; - } - public void setPublicInterface(String publicInterface) { this.publicInterface = publicInterface; } diff --git a/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java b/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java index 987e937952d..c4f0ef392ef 100644 --- a/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java +++ b/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java @@ -353,18 +353,17 @@ StaticNatServiceProvider { public ExternalLoadBalancerDeviceVO configureNetscalerLoadBalancer(ConfigureNetscalerLoadBalancerCmd cmd) { Long lbDeviceId = cmd.getLoadBalancerDeviceId(); Boolean dedicatedUse = cmd.getLoadBalancerDedicated(); - Boolean inline = cmd.getLoadBalancerInline(); Long capacity = cmd.getLoadBalancerCapacity(); List podIds = cmd.getPodIds(); try { - return configureNetscalerLoadBalancer(lbDeviceId, capacity, inline, dedicatedUse, podIds); + return configureNetscalerLoadBalancer(lbDeviceId, capacity, dedicatedUse, podIds); } catch (Exception e) { throw new CloudRuntimeException("failed to configure netscaler device due to " + e.getMessage()); } } @DB - private ExternalLoadBalancerDeviceVO configureNetscalerLoadBalancer(long lbDeviceId, Long capacity, Boolean inline, Boolean dedicatedUse, List newPodsConfig) { + private ExternalLoadBalancerDeviceVO configureNetscalerLoadBalancer(long lbDeviceId, Long capacity, Boolean dedicatedUse, List newPodsConfig) { ExternalLoadBalancerDeviceVO lbDeviceVo = _lbDeviceDao.findById(lbDeviceId); Map lbDetails = _detailsDao.findDetails(lbDeviceVo.getHostId()); @@ -404,7 +403,7 @@ StaticNatServiceProvider { } String deviceName = lbDeviceVo.getDeviceName(); - if (dedicatedUse != null || capacity != null || inline != null) { + if (dedicatedUse != null || capacity != null) { if (NetworkDevice.NetscalerSDXLoadBalancer.getName().equalsIgnoreCase(deviceName) || NetworkDevice.NetscalerMPXLoadBalancer.getName().equalsIgnoreCase(deviceName)) { if (dedicatedUse != null && dedicatedUse == true) { @@ -422,13 +421,6 @@ StaticNatServiceProvider { if (dedicatedUse != null && dedicatedUse == true) { throw new CloudRuntimeException("There are networks already using this netscaler device to make device dedicated"); } - - if (inline != null) { - boolean _setInline = Boolean.parseBoolean(lbDetails.get("inline")); - if (inline != _setInline) { - throw new CloudRuntimeException("There are networks already using this netscaler device to change the device inline or side-by-side configuration"); - } - } } } @@ -444,14 +436,6 @@ StaticNatServiceProvider { lbDeviceVo.setIsDedicatedDevice(dedicatedUse); } - if (inline != null && inline == true) { - lbDeviceVo.setIsInlineMode(true); - lbDetails.put("inline", "true"); - } else { - lbDeviceVo.setIsInlineMode(false); - lbDetails.put("inline", "false"); - } - Transaction txn = Transaction.currentTxn(); txn.start(); @@ -552,7 +536,6 @@ StaticNatServiceProvider { } else { response.setDeviceCapacity(lbDeviceVO.getCapacity()); } - response.setInlineMode(lbDeviceVO.getIsInLineMode()); response.setDedicatedLoadBalancer(lbDeviceVO.getIsDedicatedDevice()); response.setProvider(lbDeviceVO.getProviderName()); response.setDeviceState(lbDeviceVO.getState().name()); @@ -690,7 +673,7 @@ StaticNatServiceProvider { List destinations = rule.getDestinations(); if ((destinations != null && !destinations.isEmpty()) || rule.isAutoScaleConfig()) { - LoadBalancerTO loadBalancer = new LoadBalancerTO(lbUuid, srcIp, srcPort, protocol, algorithm, revoked, false, destinations, rule.getStickinessPolicies()); + LoadBalancerTO loadBalancer = new LoadBalancerTO(lbUuid, srcIp, srcPort, protocol, algorithm, revoked, false, false, destinations, rule.getStickinessPolicies()); if (rule.isAutoScaleConfig()) { loadBalancer.setAutoScaleVmGroup(rule.getAutoScaleVmGroup()); } diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 8f9837f54a5..e3450e95629 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -3006,6 +3006,11 @@ public class ApiResponseHelper implements ResponseGenerator { eLb.setValue(offering.getElasticLb() ? "true" : "false"); lbCapResponse.add(eLb); + CapabilityResponse inline = new CapabilityResponse(); + inline.setName(Capability.InlineMode.getName()); + inline.setValue(offering.isInline() ? "true" : "false"); + lbCapResponse.add(inline); + svcRsp.setCapabilities(lbCapResponse); } else if (Service.SourceNat == service) { List capabilities = new ArrayList(); diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index c7a5d64ac7e..de0931f4728 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -3099,8 +3099,8 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura void validateLoadBalancerServiceCapabilities(Map lbServiceCapabilityMap) { if (lbServiceCapabilityMap != null && !lbServiceCapabilityMap.isEmpty()) { - if (lbServiceCapabilityMap.keySet().size() > 2 || !lbServiceCapabilityMap.containsKey(Capability.SupportedLBIsolation)) { - throw new InvalidParameterValueException("Only " + Capability.SupportedLBIsolation.getName() + " and " + Capability.ElasticLb + " capabilities can be sepcified for LB service"); + if (lbServiceCapabilityMap.keySet().size() > 3 || !lbServiceCapabilityMap.containsKey(Capability.SupportedLBIsolation)) { + throw new InvalidParameterValueException("Only " + Capability.SupportedLBIsolation.getName() + ", " + Capability.ElasticLb.getName() + ", " + Capability.InlineMode.getName() + " capabilities can be sepcified for LB service"); } for (Capability cap : lbServiceCapabilityMap.keySet()) { @@ -3117,8 +3117,14 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura if (!enabled && !disabled) { throw new InvalidParameterValueException("Unknown specified value for " + Capability.ElasticLb.getName()); } + } else if (cap == Capability.InlineMode) { + boolean enabled = value.contains("true"); + boolean disabled = value.contains("false"); + if (!enabled && !disabled) { + throw new InvalidParameterValueException("Unknown specified value for " + Capability.InlineMode.getName()); + } } else { - throw new InvalidParameterValueException("Only " + Capability.SupportedLBIsolation.getName() + " and " + Capability.ElasticLb + " capabilities can be sepcified for LB service"); + throw new InvalidParameterValueException("Only " + Capability.SupportedLBIsolation.getName() + ", " + Capability.ElasticLb.getName() + ", " + Capability.InlineMode.getName() + " capabilities can be sepcified for LB service"); } } } @@ -3234,6 +3240,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura boolean redundantRouter = false; boolean elasticIp = false; boolean associatePublicIp = false; + boolean inline = false; if (serviceCapabilityMap != null && !serviceCapabilityMap.isEmpty()) { Map lbServiceCapabilityMap = serviceCapabilityMap.get(Service.Lb); @@ -3250,6 +3257,14 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura if (param != null) { elasticLb = param.contains("true"); } + + String inlineMode = lbServiceCapabilityMap.get(Capability.InlineMode); + if (inlineMode != null) { + _networkMgr.checkCapabilityForProvider(serviceProviderMap.get(Service.Lb), Service.Lb, Capability.InlineMode, inlineMode); + inline = inlineMode.contains("true"); + } else { + inline = false; + } } Map sourceNatServiceCapabilityMap = serviceCapabilityMap.get(Service.SourceNat); @@ -3284,7 +3299,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura NetworkOfferingVO offering = new NetworkOfferingVO(name, displayText, trafficType, systemOnly, specifyVlan, networkRate, multicastRate, isDefault, availability, tags, type, conserveMode, dedicatedLb, - sharedSourceNat, redundantRouter, elasticIp, elasticLb, associatePublicIp, specifyIpRanges); + sharedSourceNat, redundantRouter, elasticIp, elasticLb, associatePublicIp, specifyIpRanges, inline); if (serviceOfferingId != null) { offering.setServiceOfferingId(serviceOfferingId); diff --git a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java index 8c69bf6d852..839f8023220 100644 --- a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java +++ b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java @@ -239,7 +239,6 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase if (host != null) { boolean dedicatedUse = (configParams.get(ApiConstants.LOAD_BALANCER_DEVICE_DEDICATED) != null) ? Boolean.parseBoolean(configParams.get(ApiConstants.LOAD_BALANCER_DEVICE_DEDICATED)) : false; - boolean inline = (configParams.get(ApiConstants.INLINE) != null) ? Boolean.parseBoolean(configParams.get(ApiConstants.INLINE)) : false; long capacity = NumbersUtil.parseLong(configParams.get(ApiConstants.LOAD_BALANCER_DEVICE_CAPACITY), 0); if (capacity == 0) { capacity = _defaultLbCapacity; @@ -247,7 +246,7 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase txn.start(); ExternalLoadBalancerDeviceVO lbDeviceVO = new ExternalLoadBalancerDeviceVO(host.getId(), pNetwork.getId(), ntwkSvcProvider.getProviderName(), - deviceName, capacity, dedicatedUse, inline); + deviceName, capacity, dedicatedUse); _externalLoadBalancerDeviceDao.persist(lbDeviceVO); DetailVO hostDetail = new DetailVO(host.getId(), ApiConstants.LOAD_BALANCER_DEVICE_ID, String.valueOf(lbDeviceVO.getId())); @@ -708,11 +707,6 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase return fwHost; } - private boolean externalLoadBalancerIsInline(HostVO externalLoadBalancer) { - DetailVO detail = _hostDetailDao.findDetail(externalLoadBalancer.getId(), "inline"); - return (detail != null && detail.getValue().equals("true")); - } - private NicVO savePlaceholderNic(Network network, String ipAddress) { NicVO nic = new NicVO(null, null, network.getId(), null); nic.setIp4Address(ipAddress); @@ -786,7 +780,7 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase HostVO externalLoadBalancer = _hostDao.findById(lbDeviceVO.getHostId()); - boolean externalLoadBalancerIsInline = externalLoadBalancerIsInline(externalLoadBalancer); + boolean externalLoadBalancerIsInline = _networkMgr.isNetworkInlineMode(network); if (network.getState() == Network.State.Allocated) { s_logger.debug("External load balancer was asked to apply LB rules for network with ID " + network.getId() + "; this network is not implemented. Skipping backend commands."); @@ -867,7 +861,8 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase } if ((destinations != null && !destinations.isEmpty()) || rule.isAutoScaleConfig()) { - LoadBalancerTO loadBalancer = new LoadBalancerTO(uuid, srcIp, srcPort, protocol, algorithm, revoked, false, destinations, rule.getStickinessPolicies()); + boolean inline = _networkMgr.isNetworkInlineMode(network); + LoadBalancerTO loadBalancer = new LoadBalancerTO(uuid, srcIp, srcPort, protocol, algorithm, revoked, false, inline, destinations, rule.getStickinessPolicies()); if(rule.isAutoScaleConfig()) { loadBalancer.setAutoScaleVmGroup(rule.getAutoScaleVmGroup()); } @@ -951,7 +946,9 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase selfIp = selfipNic.getIp4Address(); } - IpAddressTO ip = new IpAddressTO(guestConfig.getAccountId(), null, add, false, true, String.valueOf(guestVlanTag), selfIp, guestVlanNetmask, null, networkRate, false); + // It's a hack, using isOneToOneNat field for indicate if it's inline or not + boolean inline = _networkMgr.isNetworkInlineMode(guestConfig); + IpAddressTO ip = new IpAddressTO(guestConfig.getAccountId(), null, add, false, true, String.valueOf(guestVlanTag), selfIp, guestVlanNetmask, null, networkRate, inline); IpAddressTO[] ips = new IpAddressTO[1]; ips[0] = ip; IpAssocCommand cmd = new IpAssocCommand(ips); diff --git a/server/src/com/cloud/network/ExternalLoadBalancerDeviceVO.java b/server/src/com/cloud/network/ExternalLoadBalancerDeviceVO.java index 190067b653b..e9414dc3bfb 100644 --- a/server/src/com/cloud/network/ExternalLoadBalancerDeviceVO.java +++ b/server/src/com/cloud/network/ExternalLoadBalancerDeviceVO.java @@ -66,9 +66,6 @@ public class ExternalLoadBalancerDeviceVO { @Column(name="is_managed") private boolean isManagedDevice; - @Column(name="is_inline") - private boolean isInlineMode; - @Column(name="is_dedicated") private boolean isDedicatedDevice; @@ -92,7 +89,7 @@ public class ExternalLoadBalancerDeviceVO { } public ExternalLoadBalancerDeviceVO(long hostId, long physicalNetworkId, String provider_name, String device_name, - long capacity, boolean dedicated, boolean inline) { + long capacity, boolean dedicated) { this.physicalNetworkId = physicalNetworkId; this.providerName = provider_name; this.deviceName = device_name; @@ -101,7 +98,6 @@ public class ExternalLoadBalancerDeviceVO { this.allocationState = LBDeviceAllocationState.Free; this.capacity = capacity; this.isDedicatedDevice = dedicated; - this.isInlineMode = inline; this.isManagedDevice = false; this.state = LBDeviceState.Enabled; this.uuid = UUID.randomUUID().toString(); @@ -112,8 +108,8 @@ public class ExternalLoadBalancerDeviceVO { } public ExternalLoadBalancerDeviceVO(long hostId, long physicalNetworkId, String provider_name, String device_name, - long capacity, boolean dedicated, boolean inline, boolean managed, long parentHostId) { - this(hostId, physicalNetworkId, provider_name, device_name, capacity, dedicated, inline); + long capacity, boolean dedicated, boolean managed, long parentHostId) { + this(hostId, physicalNetworkId, provider_name, device_name, capacity, dedicated); this.isManagedDevice = managed; this.parentHostId = parentHostId; } @@ -182,14 +178,6 @@ public class ExternalLoadBalancerDeviceVO { this.isManagedDevice = managed; } - public boolean getIsInLineMode () { - return isInlineMode; - } - - public void setIsInlineMode(boolean inline) { - this.isInlineMode = inline; - } - public boolean getIsDedicatedDevice() { return isDedicatedDevice; } diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index 057f473e732..d52e88a45bd 100755 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -483,4 +483,5 @@ public interface NetworkManager extends NetworkService { */ int getNetworkLockTimeout(); + boolean isNetworkInlineMode(Network network); } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 3f8b08519ad..f993b2b9b72 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -7484,4 +7484,9 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag return _networkLockTimeout; } + @Override + public boolean isNetworkInlineMode(Network network) { + NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); + return offering.isInline(); + } } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 966c32de6c2..c61e97965f1 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -2835,6 +2835,8 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian LoadBalancerTO[] lbs = new LoadBalancerTO[rules.size()]; int i = 0; + // We don't support VR to be inline currently + boolean inline = false; for (LoadBalancingRule rule : rules) { boolean revoked = (rule.getState().equals(FirewallRule.State.Revoke)); String protocol = rule.getProtocol(); @@ -2845,7 +2847,7 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian int srcPort = rule.getSourcePortStart(); List destinations = rule.getDestinations(); List stickinessPolicies = rule.getStickinessPolicies(); - LoadBalancerTO lb = new LoadBalancerTO(uuid, srcIp, srcPort, protocol, algorithm, revoked, false, destinations, stickinessPolicies); + LoadBalancerTO lb = new LoadBalancerTO(uuid, srcIp, srcPort, protocol, algorithm, revoked, false, false, destinations, stickinessPolicies); lbs[i++] = lb; } String routerPublicIp = null; diff --git a/server/src/com/cloud/offerings/NetworkOfferingVO.java b/server/src/com/cloud/offerings/NetworkOfferingVO.java index 2570b70f630..100a52935b8 100755 --- a/server/src/com/cloud/offerings/NetworkOfferingVO.java +++ b/server/src/com/cloud/offerings/NetworkOfferingVO.java @@ -117,6 +117,9 @@ public class NetworkOfferingVO implements NetworkOffering, Identity { @Column(name = "eip_associate_public_ip") boolean eipAssociatePublicIp; + @Column(name = "inline") + boolean inline; + @Override public String getDisplayText() { return displayText; @@ -278,12 +281,13 @@ public class NetworkOfferingVO implements NetworkOffering, Identity { this.elasticIp = false; this.elasticLb = false; this.eipAssociatePublicIp = true; + this.inline = false; this.specifyIpRanges = specifyIpRanges; } public NetworkOfferingVO(String name, String displayText, TrafficType trafficType, boolean systemOnly, boolean specifyVlan, Integer rateMbps, Integer multicastRateMbps, boolean isDefault, Availability availability, String tags, Network.GuestType guestType, boolean conserveMode, boolean dedicatedLb, boolean sharedSourceNat, boolean redundantRouter, boolean elasticIp, boolean elasticLb, - boolean associatePublicIP, boolean specifyIpRanges) { + boolean associatePublicIP, boolean specifyIpRanges, boolean inline) { this(name, displayText, trafficType, systemOnly, specifyVlan, rateMbps, multicastRateMbps, isDefault, availability, tags, guestType, conserveMode, specifyIpRanges); this.dedicatedLB = dedicatedLb; this.sharedSourceNat = sharedSourceNat; @@ -291,6 +295,7 @@ public class NetworkOfferingVO implements NetworkOffering, Identity { this.elasticIp = elasticIp; this.elasticLb = elasticLb; this.eipAssociatePublicIp = associatePublicIP; + this.inline = inline; } public NetworkOfferingVO() { @@ -367,4 +372,8 @@ public class NetworkOfferingVO implements NetworkOffering, Identity { return specifyIpRanges; } + @Override + public boolean isInline() { + return inline; + } } diff --git a/server/src/com/cloud/server/ConfigurationServerImpl.java b/server/src/com/cloud/server/ConfigurationServerImpl.java index c0c29ed8eb8..43a1d99c888 100755 --- a/server/src/com/cloud/server/ConfigurationServerImpl.java +++ b/server/src/com/cloud/server/ConfigurationServerImpl.java @@ -971,7 +971,7 @@ public class ConfigurationServerImpl implements ConfigurationServer { "Offering for Shared networks with Elastic IP and Elastic LB capabilities", TrafficType.Guest, false, true, null, null, true, Availability.Optional, - null, Network.GuestType.Shared, true, false, false, false, true, true, true, true); + null, Network.GuestType.Shared, true, false, false, false, true, true, true, true, false); defaultNetscalerNetworkOffering.setState(NetworkOffering.State.Enabled); defaultNetscalerNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultNetscalerNetworkOffering); diff --git a/server/test/com/cloud/network/MockNetworkManagerImpl.java b/server/test/com/cloud/network/MockNetworkManagerImpl.java index 76b911a722e..d8ef9e4cfbe 100755 --- a/server/test/com/cloud/network/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/network/MockNetworkManagerImpl.java @@ -1135,4 +1135,10 @@ public class MockNetworkManagerImpl implements NetworkManager, Manager, NetworkS // TODO Auto-generated method stub return 0; } + + @Override + public boolean isNetworkInlineMode(Network network) { + // TODO Auto-generated method stub + return false; + } } diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java index 3536d66ea4f..2141c1b0e09 100644 --- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java @@ -1480,4 +1480,9 @@ public class MockNetworkManagerImpl implements NetworkManager, Manager{ return 0; } + @Override + public boolean isNetworkInlineMode(Network network) { + // TODO Auto-generated method stub + return false; + } } diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index 1b6ee5df112..fb00ed4cd37 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -308,6 +308,7 @@ CREATE TABLE `cloud`.`network_offerings` ( `eip_associate_public_ip` int(1) unsigned NOT NULL DEFAULT 0 COMMENT 'true if public IP is associated with user VM creation by default when EIP service is enabled.', `elastic_lb_service` int(1) unsigned NOT NULL DEFAULT 0 COMMENT 'true if the network offering provides elastic lb service', `specify_ip_ranges` int(1) unsigned NOT NULL DEFAULT 0 COMMENT 'true if the network offering provides an ability to define ip ranges', + `inline` int(1) unsigned NOT NULL DEFAULT 0 COMMENT 'Is this network offering LB provider is in inline mode', PRIMARY KEY (`id`), INDEX `i_network_offerings__system_only`(`system_only`), INDEX `i_network_offerings__removed`(`removed`), @@ -2075,7 +2076,6 @@ CREATE TABLE `cloud`.`external_load_balancer_devices` ( `device_state` varchar(32) NOT NULL DEFAULT 'Disabled' COMMENT 'state (enabled/disabled/shutdown) of the device', `allocation_state` varchar(32) NOT NULL DEFAULT 'Free' COMMENT 'Allocation state (Free/Shared/Dedicated/Provider) of the device', `is_dedicated` int(1) unsigned NOT NULL DEFAULT 0 COMMENT '1 if device/appliance is provisioned for dedicated use only', - `is_inline` int(1) unsigned NOT NULL DEFAULT 0 COMMENT '1 if load balancer will be used in in-line configuration with firewall', `is_managed` int(1) unsigned NOT NULL DEFAULT 0 COMMENT '1 if load balancer appliance is provisioned and its life cycle is managed by by cloudstack', `host_id` bigint unsigned NOT NULL COMMENT 'host id coresponding to the external load balancer device', `parent_host_id` bigint unsigned COMMENT 'if the load balancer appliance is cloudstack managed, then host id on which this appliance is provisioned', diff --git a/setup/db/db/schema-40to410.sql b/setup/db/db/schema-40to410.sql index b09ebb94fea..2ce86e0b894 100644 --- a/setup/db/db/schema-40to410.sql +++ b/setup/db/db/schema-40to410.sql @@ -57,6 +57,9 @@ ALTER TABLE `cloud`.`snapshots` ADD COLUMN `s3_id` bigint unsigned COMMENT 'S3 t ALTER TABLE `cloud`.`snapshots` ADD CONSTRAINT `fk_snapshots__s3_id` FOREIGN KEY `fk_snapshots__s3_id` (`s3_id`) REFERENCES `s3` (`id`); ALTER TABLE `cloud`.`network_offerings` ADD COLUMN `eip_associate_public_ip` int(1) unsigned NOT NULL DEFAULT 0 COMMENT 'true if public IP is associated with user VM creation by default when EIP service is enabled.' AFTER `elastic_ip_service`; +ALTER TABLE `cloud`.`network_offerings` ADD COLUMN `inline` int(1) unsigned NOT NULL DEFAULT 0 COMMENT 'Is this network offering LB provider is in inline mode'; + +ALTER TABLE `cloud`.`external_load_balancer_devices` DROP COLUMN `is_inline`; INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Network','DEFAULT','NetworkManager','network.dhcp.nondefaultnetwork.setgateway.guestos','Windows','The guest OS\'s name start with this fields would result in DHCP server response gateway information even when the network it\'s on is not default network. Names are separated by comma.'); From 42c8c73ab6437d86578f7f6d7b48a96a2de29bec Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Fri, 4 Jan 2013 18:56:47 -0800 Subject: [PATCH 3/5] CLOUDSTACK-306: Introducing IpDeployingRequester and implement inline mode For LB device in inline mode, the ip deployer(the owner of public ip) is the firewall in front of it, not itself. So check if it's inline or not, if it's inline, return the firewall as ip deployer --- .../com/cloud/network/element/IpDeployer.java | 3 + .../network/element/IpDeployingRequester.java | 28 ++ .../element/LoadBalancingServiceProvider.java | 3 +- .../PortForwardingServiceProvider.java | 4 +- .../RemoteAccessVPNServiceProvider.java | 4 +- .../element/SourceNatServiceProvider.java | 5 +- .../element/StaticNatServiceProvider.java | 4 +- .../F5ExternalLoadBalancerElement.java | 12 +- .../network/resource/F5BigIpResource.java | 9 +- .../JuniperSRXExternalFirewallElement.java | 19 +- .../network/element/NetscalerElement.java | 8 + ...ExternalLoadBalancerDeviceManagerImpl.java | 303 +++++++++++------- .../network/InlineLoadBalancerNicMapVO.java | 10 +- .../src/com/cloud/network/NetworkManager.java | 10 + .../com/cloud/network/NetworkManagerImpl.java | 213 +++++++----- .../cloud/network/dao/FirewallRulesDao.java | 4 +- .../network/dao/FirewallRulesDaoImpl.java | 15 + .../lb/LoadBalancingRulesManagerImpl.java | 16 +- .../cloud/network/MockNetworkManagerImpl.java | 29 ++ .../com/cloud/vpc/MockNetworkManagerImpl.java | 28 ++ setup/db/create-schema.sql | 2 - setup/db/db/schema-40to410.sql | 4 + 22 files changed, 508 insertions(+), 225 deletions(-) create mode 100644 api/src/com/cloud/network/element/IpDeployingRequester.java diff --git a/api/src/com/cloud/network/element/IpDeployer.java b/api/src/com/cloud/network/element/IpDeployer.java index 3eebe82cf2e..55b21abe9ab 100644 --- a/api/src/com/cloud/network/element/IpDeployer.java +++ b/api/src/com/cloud/network/element/IpDeployer.java @@ -21,6 +21,7 @@ import java.util.Set; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.Network; +import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; import com.cloud.network.PublicIpAddress; @@ -33,4 +34,6 @@ public interface IpDeployer { * @throws ResourceUnavailableException */ boolean applyIps(Network network, List ipAddress, Set services) throws ResourceUnavailableException; + + Provider getProvider(); } diff --git a/api/src/com/cloud/network/element/IpDeployingRequester.java b/api/src/com/cloud/network/element/IpDeployingRequester.java new file mode 100644 index 00000000000..01a11b570c1 --- /dev/null +++ b/api/src/com/cloud/network/element/IpDeployingRequester.java @@ -0,0 +1,28 @@ +// 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 com.cloud.network.element; + +import com.cloud.network.Network; + +public interface IpDeployingRequester { + /** + * Would return the IpDeployer can deploy IP for this element + * @param network + * @return IpDeployer object, or null if there is no deployer for this element + */ + IpDeployer getIpDeployer(Network network); +} diff --git a/api/src/com/cloud/network/element/LoadBalancingServiceProvider.java b/api/src/com/cloud/network/element/LoadBalancingServiceProvider.java index 3c5474642a4..c577c263a8d 100644 --- a/api/src/com/cloud/network/element/LoadBalancingServiceProvider.java +++ b/api/src/com/cloud/network/element/LoadBalancingServiceProvider.java @@ -22,7 +22,7 @@ import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.Network; import com.cloud.network.lb.LoadBalancingRule; -public interface LoadBalancingServiceProvider extends NetworkElement { +public interface LoadBalancingServiceProvider extends NetworkElement, IpDeployingRequester { /** * Apply rules * @param network @@ -32,7 +32,6 @@ public interface LoadBalancingServiceProvider extends NetworkElement { */ boolean applyLBRules(Network network, List rules) throws ResourceUnavailableException; - IpDeployer getIpDeployer(Network network); /** * Validate rules * @param network diff --git a/api/src/com/cloud/network/element/PortForwardingServiceProvider.java b/api/src/com/cloud/network/element/PortForwardingServiceProvider.java index d6589515d2a..e99bc2fd416 100644 --- a/api/src/com/cloud/network/element/PortForwardingServiceProvider.java +++ b/api/src/com/cloud/network/element/PortForwardingServiceProvider.java @@ -22,7 +22,7 @@ import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.Network; import com.cloud.network.rules.PortForwardingRule; -public interface PortForwardingServiceProvider extends NetworkElement { +public interface PortForwardingServiceProvider extends NetworkElement, IpDeployingRequester { /** * Apply rules * @param network @@ -31,6 +31,4 @@ public interface PortForwardingServiceProvider extends NetworkElement { * @throws ResourceUnavailableException */ boolean applyPFRules(Network network, List rules) 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 d799b0bf4e3..b4c54cbaa93 100644 --- a/api/src/com/cloud/network/element/RemoteAccessVPNServiceProvider.java +++ b/api/src/com/cloud/network/element/RemoteAccessVPNServiceProvider.java @@ -23,12 +23,10 @@ import com.cloud.network.Network; import com.cloud.network.RemoteAccessVpn; import com.cloud.network.VpnUser; -public interface RemoteAccessVPNServiceProvider extends NetworkElement { +public interface RemoteAccessVPNServiceProvider extends NetworkElement, IpDeployingRequester { String[] applyVpnUsers(RemoteAccessVpn vpn, List users) throws ResourceUnavailableException; 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 af63c6018b9..eaf43f82edd 100644 --- a/api/src/com/cloud/network/element/SourceNatServiceProvider.java +++ b/api/src/com/cloud/network/element/SourceNatServiceProvider.java @@ -16,8 +16,5 @@ // under the License. package com.cloud.network.element; -import com.cloud.network.Network; - -public interface SourceNatServiceProvider extends NetworkElement { - IpDeployer getIpDeployer(Network network); +public interface SourceNatServiceProvider extends NetworkElement, IpDeployingRequester { } diff --git a/api/src/com/cloud/network/element/StaticNatServiceProvider.java b/api/src/com/cloud/network/element/StaticNatServiceProvider.java index 20174b17251..50f5e204658 100644 --- a/api/src/com/cloud/network/element/StaticNatServiceProvider.java +++ b/api/src/com/cloud/network/element/StaticNatServiceProvider.java @@ -22,7 +22,7 @@ import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.Network; import com.cloud.network.rules.StaticNat; -public interface StaticNatServiceProvider extends NetworkElement { +public interface StaticNatServiceProvider extends NetworkElement, IpDeployingRequester { /** * Creates static nat rule (public IP to private IP mapping) on the network element * @param config @@ -31,6 +31,4 @@ public interface StaticNatServiceProvider extends NetworkElement { * @throws ResourceUnavailableException */ boolean applyStaticNats(Network config, List rules) throws ResourceUnavailableException; - - IpDeployer getIpDeployer(Network network); } diff --git a/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java b/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java index 63e82751b4d..a2d96ef5ace 100644 --- a/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java +++ b/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java @@ -172,7 +172,8 @@ public class F5ExternalLoadBalancerElement extends ExternalLoadBalancerDeviceMan @Override public boolean validateLBRule(Network network, LoadBalancingRule rule) { - return true; + String algo = rule.getAlgorithm(); + return (algo.equals("roundrobin") || algo.equals("leastconn")); } @Override @@ -471,6 +472,15 @@ public class F5ExternalLoadBalancerElement extends ExternalLoadBalancerDeviceMan @Override public IpDeployer getIpDeployer(Network network) { + ExternalLoadBalancerDeviceVO lbDevice = getExternalLoadBalancerForNetwork(network); + if (lbDevice == null) { + s_logger.error("Cannot find external load balanacer for network " + network.getName()); + s_logger.error("Make F5 as dummy ip deployer, since we likely met this when clean up resource after shutdown network"); + return this; + } + if (_networkManager.isNetworkInlineMode(network)) { + return getIpDeployerForInlineMode(network); + } return this; } } diff --git a/plugins/network-elements/f5/src/com/cloud/network/resource/F5BigIpResource.java b/plugins/network-elements/f5/src/com/cloud/network/resource/F5BigIpResource.java index 618cd912e91..c9c3711bfc1 100644 --- a/plugins/network-elements/f5/src/com/cloud/network/resource/F5BigIpResource.java +++ b/plugins/network-elements/f5/src/com/cloud/network/resource/F5BigIpResource.java @@ -296,7 +296,6 @@ public class F5BigIpResource implements ServerResource { for (IpAddressTO ip : ips) { long guestVlanTag = Long.valueOf(ip.getVlanId()); // It's a hack, using isOneToOneNat field for indicate if it's inline or not - // We'd better have an separate SetupGuestNetwork command later boolean inline = ip.isOneToOneNat(); String vlanSelfIp = inline ? tagAddressWithRouteDomain(ip.getVlanGateway(), guestVlanTag) : ip.getVlanGateway(); String vlanNetmask = ip.getVlanNetmask(); @@ -364,6 +363,8 @@ public class F5BigIpResource implements ServerResource { } } + // Delete the virtual server with this protocol, source IP, and source port, along with its default pool and all pool members + deleteVirtualServerAndDefaultPool(virtualServerName); if (!loadBalancer.isRevoked() && destinationsToAdd) { // Add the pool addPool(virtualServerName, lbAlgorithm); @@ -378,14 +379,8 @@ public class F5BigIpResource implements ServerResource { } } - // Delete any pool members that aren't in the current list of destinations - deleteInactivePoolMembers(virtualServerName, activePoolMembers); - // Add the virtual server addVirtualServer(virtualServerName, lbProtocol, srcIp, srcPort, loadBalancer.getStickinessPolicies()); - } else { - // Delete the virtual server with this protocol, source IP, and source port, along with its default pool and all pool members - deleteVirtualServerAndDefaultPool(virtualServerName); } } diff --git a/plugins/network-elements/juniper-srx/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java b/plugins/network-elements/juniper-srx/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java index 50c088c2447..ccc60cf14de 100644 --- a/plugins/network-elements/juniper-srx/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java +++ b/plugins/network-elements/juniper-srx/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java @@ -76,6 +76,7 @@ import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.resource.JuniperSrxResource; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.PortForwardingRule; +import com.cloud.network.rules.StaticNat; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.resource.ServerResource; @@ -90,7 +91,7 @@ import com.cloud.vm.VirtualMachineProfile; @Local(value = NetworkElement.class) public class JuniperSRXExternalFirewallElement extends ExternalFirewallDeviceManagerImpl implements SourceNatServiceProvider, FirewallServiceProvider, - PortForwardingServiceProvider, RemoteAccessVPNServiceProvider, IpDeployer, JuniperSRXFirewallElementService { + PortForwardingServiceProvider, RemoteAccessVPNServiceProvider, IpDeployer, JuniperSRXFirewallElementService, StaticNatServiceProvider { private static final Logger s_logger = Logger.getLogger(JuniperSRXExternalFirewallElement.class); @@ -302,7 +303,7 @@ public class JuniperSRXExternalFirewallElement extends ExternalFirewallDeviceMan return false; } - return applyFirewallRules(network, rules); + return applyPortForwardingRules(network, rules); } @Override @@ -329,7 +330,7 @@ public class JuniperSRXExternalFirewallElement extends ExternalFirewallDeviceMan @Override public boolean canEnableIndividualServices() { - return false; + return true; } @Override @@ -534,6 +535,10 @@ public class JuniperSRXExternalFirewallElement extends ExternalFirewallDeviceMan @Override public boolean verifyServicesCombination(Set services) { + if (!services.contains(Service.Firewall)) { + s_logger.warn("SRX must be used as Firewall Service Provider in the network"); + return false; + } return true; } @@ -547,4 +552,12 @@ public class JuniperSRXExternalFirewallElement extends ExternalFirewallDeviceMan // return true, as IP will be associated as part of static NAT/port forwarding rule configuration return true; } + + @Override + public boolean applyStaticNats(Network config, List rules) throws ResourceUnavailableException { + if (!canHandle(config, Service.StaticNat)) { + return false; + } + return applyStaticNatRules(config, rules); + } } diff --git a/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java b/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java index c4f0ef392ef..6e7d4e5fb84 100644 --- a/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java +++ b/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java @@ -627,6 +627,14 @@ StaticNatServiceProvider { @Override public IpDeployer getIpDeployer(Network network) { + ExternalLoadBalancerDeviceVO lbDevice = getExternalLoadBalancerForNetwork(network); + if (lbDevice == null) { + s_logger.error("Cannot find external load balanacer for network " + network.getName()); + return null; + } + if (_networkMgr.isNetworkInlineMode(network)) { + return getIpDeployerForInlineMode(network); + } return this; } diff --git a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java index 839f8023220..c37d53f6dbc 100644 --- a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java +++ b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java @@ -64,6 +64,7 @@ import com.cloud.host.dao.HostDetailsDao; import com.cloud.network.ExternalLoadBalancerDeviceVO.LBDeviceAllocationState; import com.cloud.network.ExternalLoadBalancerDeviceVO.LBDeviceState; import com.cloud.network.ExternalNetworkDeviceManager.NetworkDevice; +import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; import com.cloud.network.Networks.TrafficType; import com.cloud.network.addr.PublicIp; @@ -79,6 +80,9 @@ import com.cloud.network.dao.NetworkServiceMapDao; import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; import com.cloud.network.dao.PhysicalNetworkServiceProviderVO; +import com.cloud.network.element.IpDeployer; +import com.cloud.network.element.NetworkElement; +import com.cloud.network.element.StaticNatServiceProvider; import com.cloud.network.lb.LoadBalancingRule; import com.cloud.network.lb.LoadBalancingRule.LbDestination; import com.cloud.network.resource.CreateLoadBalancerApplianceAnswer; @@ -86,6 +90,8 @@ import com.cloud.network.resource.DestroyLoadBalancerApplianceAnswer; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.FirewallRuleVO; +import com.cloud.network.rules.StaticNat; +import com.cloud.network.rules.StaticNatImpl; import com.cloud.network.rules.StaticNatRule; import com.cloud.network.rules.StaticNatRuleImpl; import com.cloud.network.rules.dao.PortForwardingRulesDao; @@ -688,25 +694,6 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase return false; } - HostVO getFirewallProviderForNetwork(Network network) { - HostVO fwHost = null; - - // get the firewall provider (could be either virtual router or external firewall device) for the network - String fwProvider = _ntwkSrvcProviderDao.getProviderForServiceInNetwork(network.getId(), Service.Firewall); - - if (fwProvider.equalsIgnoreCase("VirtualRouter")) { - // FIXME: use network service provider container framework support to implement on virtual router - } else { - NetworkExternalFirewallVO fwDeviceForNetwork = _networkExternalFirewallDao.findByNetworkId(network.getId()); - assert (fwDeviceForNetwork != null) : "Why firewall provider is not ready for the network to apply static nat rules?"; - long fwDeviceId = fwDeviceForNetwork.getExternalFirewallDeviceId(); - ExternalFirewallDeviceVO fwDevice = _externalFirewallDeviceDao.findById(fwDeviceId); - fwHost = _hostDao.findById(fwDevice.getHostId()); - } - - return fwHost; - } - private NicVO savePlaceholderNic(Network network, String ipAddress) { NicVO nic = new NicVO(null, null, network.getId(), null); nic.setIp4Address(ipAddress); @@ -727,31 +714,115 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase return null; } - private void applyStaticNatRuleForInlineLBRule(DataCenterVO zone, Network network, HostVO firewallHost, boolean revoked, String publicIp, String privateIp) throws ResourceUnavailableException { - List staticNatRules = new ArrayList(); + private void applyStaticNatRuleForInlineLBRule(DataCenterVO zone, Network network, boolean revoked, String publicIp, String privateIp) throws ResourceUnavailableException { + List staticNats = new ArrayList(); IPAddressVO ipVO = _ipAddressDao.listByDcIdIpAddress(zone.getId(), publicIp).get(0); - VlanVO vlan = _vlanDao.findById(ipVO.getVlanId()); - FirewallRuleVO fwRule = new FirewallRuleVO(null, ipVO.getId(), -1, -1, "any", network.getId(), network.getAccountId(), network.getDomainId(), Purpose.StaticNat, null, null, null, null, null); - FirewallRule.State state = !revoked ? FirewallRule.State.Add : FirewallRule.State.Revoke; - fwRule.setState(state); - StaticNatRule rule = new StaticNatRuleImpl(fwRule, privateIp); - StaticNatRuleTO ruleTO = new StaticNatRuleTO(rule, vlan.getVlanTag(), publicIp, privateIp); - staticNatRules.add(ruleTO); - - applyStaticNatRules(staticNatRules, network, firewallHost.getId()); + StaticNatImpl staticNat = new StaticNatImpl(ipVO.getAllocatedToAccountId(), ipVO.getAllocatedInDomainId(), + network.getId(), ipVO.getId(), privateIp, revoked); + staticNats.add(staticNat); + StaticNatServiceProvider element = _networkMgr.getStaticNatProviderForNetwork(network); + element.applyStaticNats(network, staticNats); } - protected void applyStaticNatRules(List staticNatRules, Network network, long firewallHostId) throws ResourceUnavailableException { - if (!staticNatRules.isEmpty()) { - SetStaticNatRulesCommand cmd = new SetStaticNatRulesCommand(staticNatRules, null); - Answer answer = _agentMgr.easySend(firewallHostId, cmd); - if (answer == null || !answer.getResult()) { - String details = (answer != null) ? answer.getDetails() : "details unavailable"; - String msg = "firewall provider for the network was unable to apply static nat rules due to: " + details + "."; - s_logger.error(msg); - throw new ResourceUnavailableException(msg, Network.class, network.getId()); + private enum MappingState { + Create, + Remove, + Unchanged, + }; + + private class MappingNic { + private NicVO nic; + private MappingState state; + + public NicVO getNic() { + return nic; + } + public void setNic(NicVO nic) { + this.nic = nic; + } + public MappingState getState() { + return state; + } + public void setState(MappingState state) { + this.state = state; + } + }; + + private MappingNic getLoadBalancingIpNic(DataCenterVO zone, Network network, long sourceIpId, boolean revoked, String existedGuestIp) throws ResourceUnavailableException { + String srcIp = _networkMgr.getIp(sourceIpId).getAddress().addr(); + InlineLoadBalancerNicMapVO mapping = _inlineLoadBalancerNicMapDao.findByPublicIpAddress(srcIp); + NicVO loadBalancingIpNic = null; + MappingNic nic = new MappingNic(); + nic.setState(MappingState.Unchanged); + if (!revoked) { + if (mapping == null) { + // Acquire a new guest IP address and save it as the load balancing IP address + String loadBalancingIpAddress = existedGuestIp; + + if (loadBalancingIpAddress == null) { + loadBalancingIpAddress = _networkMgr.acquireGuestIpAddress(network, null); + } + + if (loadBalancingIpAddress == null) { + String msg = "Ran out of guest IP addresses."; + s_logger.error(msg); + throw new ResourceUnavailableException(msg, DataCenter.class, network.getDataCenterId()); + } + + // If a NIC doesn't exist for the load balancing IP address, create one + loadBalancingIpNic = _nicDao.findByIp4AddressAndNetworkId(loadBalancingIpAddress, network.getId()); + if (loadBalancingIpNic == null) { + loadBalancingIpNic = savePlaceholderNic(network, loadBalancingIpAddress); + } + + // Save a mapping between the source IP address and the load balancing IP address NIC + mapping = new InlineLoadBalancerNicMapVO(srcIp, loadBalancingIpNic.getId()); + _inlineLoadBalancerNicMapDao.persist(mapping); + + // On the firewall provider for the network, create a static NAT rule between the source IP + // address and the load balancing IP address + try { + applyStaticNatRuleForInlineLBRule(zone, network, revoked, srcIp, loadBalancingIpNic.getIp4Address()); + } catch (ResourceUnavailableException ex) { + // Rollback db operation + _inlineLoadBalancerNicMapDao.expunge(mapping.getId()); + _nicDao.expunge(loadBalancingIpNic.getId()); + throw ex; + } + + s_logger.debug("Created static nat rule for inline load balancer"); + nic.setState(MappingState.Create); + } else { + loadBalancingIpNic = _nicDao.findById(mapping.getNicId()); + } + } else { + if (mapping != null) { + // Find the NIC that the mapping refers to + loadBalancingIpNic = _nicDao.findById(mapping.getNicId()); + + int count = _networkMgr.getRuleCountForIp(sourceIpId, Purpose.LoadBalancing, FirewallRule.State.Active); + if (count == 0) { + // On the firewall provider for the network, delete the static NAT rule between the source IP + // address and the load balancing IP address + applyStaticNatRuleForInlineLBRule(zone, network, revoked, srcIp, loadBalancingIpNic.getIp4Address()); + + // Delete the mapping between the source IP address and the load balancing IP address + _inlineLoadBalancerNicMapDao.expunge(mapping.getId()); + + // Delete the NIC + _nicDao.expunge(loadBalancingIpNic.getId()); + + s_logger.debug("Revoked static nat rule for inline load balancer"); + nic.setState(MappingState.Remove); + } + } else { + s_logger.debug("Revoking a rule for an inline load balancer that has not been programmed yet."); + return null; } } + + nic.setNic(loadBalancingIpNic); + return nic; } @Override @@ -788,6 +859,7 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase } List loadBalancersToApply = new ArrayList(); + List mappingStates = new ArrayList(); for (int i = 0; i < loadBalancingRules.size(); i++) { LoadBalancingRule rule = loadBalancingRules.get(i); @@ -798,62 +870,13 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase String srcIp = _networkMgr.getIp(rule.getSourceIpAddressId()).getAddress().addr(); int srcPort = rule.getSourcePortStart(); List destinations = rule.getDestinations(); - List sourceCidrs = rule.getSourceCidrList(); if (externalLoadBalancerIsInline) { - InlineLoadBalancerNicMapVO mapping = _inlineLoadBalancerNicMapDao.findByPublicIpAddress(srcIp); - NicVO loadBalancingIpNic = null; - HostVO firewallProviderHost = null; - - if (externalLoadBalancerIsInline) { - firewallProviderHost = getFirewallProviderForNetwork(network); - } - - if (!revoked) { - if (mapping == null) { - // Acquire a new guest IP address and save it as the load balancing IP address - String loadBalancingIpAddress = _networkMgr.acquireGuestIpAddress(network, null); - - if (loadBalancingIpAddress == null) { - String msg = "Ran out of guest IP addresses."; - s_logger.error(msg); - throw new ResourceUnavailableException(msg, DataCenter.class, network.getDataCenterId()); - } - - // If a NIC doesn't exist for the load balancing IP address, create one - loadBalancingIpNic = _nicDao.findByIp4AddressAndNetworkId(loadBalancingIpAddress, network.getId()); - if (loadBalancingIpNic == null) { - loadBalancingIpNic = savePlaceholderNic(network, loadBalancingIpAddress); - } - - // Save a mapping between the source IP address and the load balancing IP address NIC - mapping = new InlineLoadBalancerNicMapVO(rule.getId(), srcIp, loadBalancingIpNic.getId()); - _inlineLoadBalancerNicMapDao.persist(mapping); - - // On the firewall provider for the network, create a static NAT rule between the source IP -// address and the load balancing IP address - applyStaticNatRuleForInlineLBRule(zone, network, firewallProviderHost, revoked, srcIp, loadBalancingIpNic.getIp4Address()); - } else { - loadBalancingIpNic = _nicDao.findById(mapping.getNicId()); - } - } else { - if (mapping != null) { - // Find the NIC that the mapping refers to - loadBalancingIpNic = _nicDao.findById(mapping.getNicId()); - - // On the firewall provider for the network, delete the static NAT rule between the source IP -// address and the load balancing IP address - applyStaticNatRuleForInlineLBRule(zone, network, firewallProviderHost, revoked, srcIp, loadBalancingIpNic.getIp4Address()); - - // Delete the mapping between the source IP address and the load balancing IP address - _inlineLoadBalancerNicMapDao.expunge(mapping.getId()); - - // Delete the NIC - _nicDao.expunge(loadBalancingIpNic.getId()); - } else { - s_logger.debug("Revoking a rule for an inline load balancer that has not been programmed yet."); - continue; - } + MappingNic nic = getLoadBalancingIpNic(zone, network, rule.getSourceIpAddressId(), revoked, null); + mappingStates.add(nic.getState()); + NicVO loadBalancingIpNic = nic.getNic(); + if (loadBalancingIpNic == null) { + continue; } // Change the source IP address for the load balancing rule to be the load balancing IP address @@ -863,26 +886,48 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase if ((destinations != null && !destinations.isEmpty()) || rule.isAutoScaleConfig()) { boolean inline = _networkMgr.isNetworkInlineMode(network); LoadBalancerTO loadBalancer = new LoadBalancerTO(uuid, srcIp, srcPort, protocol, algorithm, revoked, false, inline, destinations, rule.getStickinessPolicies()); - if(rule.isAutoScaleConfig()) { + if (rule.isAutoScaleConfig()) { loadBalancer.setAutoScaleVmGroup(rule.getAutoScaleVmGroup()); } loadBalancersToApply.add(loadBalancer); } } - if (loadBalancersToApply.size() > 0) { - int numLoadBalancersForCommand = loadBalancersToApply.size(); - LoadBalancerTO[] loadBalancersForCommand = loadBalancersToApply.toArray(new LoadBalancerTO[numLoadBalancersForCommand]); - LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(loadBalancersForCommand, null); - long guestVlanTag = Integer.parseInt(network.getBroadcastUri().getHost()); - cmd.setAccessDetail(NetworkElementCommand.GUEST_VLAN_TAG, String.valueOf(guestVlanTag)); - Answer answer = _agentMgr.easySend(externalLoadBalancer.getId(), cmd); - if (answer == null || !answer.getResult()) { - String details = (answer != null) ? answer.getDetails() : "details unavailable"; - String msg = "Unable to apply load balancer rules to the external load balancer appliance in zone " + zone.getName() + " due to: " + details + "."; - s_logger.error(msg); - throw new ResourceUnavailableException(msg, DataCenter.class, network.getDataCenterId()); + try { + if (loadBalancersToApply.size() > 0) { + int numLoadBalancersForCommand = loadBalancersToApply.size(); + LoadBalancerTO[] loadBalancersForCommand = loadBalancersToApply.toArray(new LoadBalancerTO[numLoadBalancersForCommand]); + LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(loadBalancersForCommand, null); + long guestVlanTag = Integer.parseInt(network.getBroadcastUri().getHost()); + cmd.setAccessDetail(NetworkElementCommand.GUEST_VLAN_TAG, String.valueOf(guestVlanTag)); + Answer answer = _agentMgr.easySend(externalLoadBalancer.getId(), cmd); + if (answer == null || !answer.getResult()) { + String details = (answer != null) ? answer.getDetails() : "details unavailable"; + String msg = "Unable to apply load balancer rules to the external load balancer appliance in zone " + zone.getName() + " due to: " + details + "."; + s_logger.error(msg); + throw new ResourceUnavailableException(msg, DataCenter.class, network.getDataCenterId()); + } } + } catch (Exception ex) { + if (externalLoadBalancerIsInline) { + s_logger.error("Rollbacking static nat operation of inline mode load balancing due to error on applying LB rules!"); + String existedGuestIp = loadBalancersToApply.get(0).getSrcIp(); + // Rollback static NAT operation in current session + for (int i = 0; i < loadBalancingRules.size(); i++) { + LoadBalancingRule rule = loadBalancingRules.get(i); + MappingState state = mappingStates.get(i); + boolean revoke; + if (state == MappingState.Create) { + revoke = true; + } else if (state == MappingState.Remove) { + revoke = false; + } else { + continue; + } + getLoadBalancingIpNic(zone, network, rule.getSourceIpAddressId(), revoke, existedGuestIp); + } + } + throw new ResourceUnavailableException(ex.getMessage(), DataCenter.class, network.getDataCenterId()); } return true; @@ -900,11 +945,17 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase HostVO externalLoadBalancer = null; if (add) { - ExternalLoadBalancerDeviceVO lbDeviceVO = allocateLoadBalancerForNetwork(guestConfig); + ExternalLoadBalancerDeviceVO lbDeviceVO = null; + // on restart network, device could have been allocated already, skip allocation if a device is assigned + lbDeviceVO = getExternalLoadBalancerForNetwork(guestConfig); if (lbDeviceVO == null) { - String msg = "failed to alloacate a external load balancer for the network " + guestConfig.getId(); - s_logger.error(msg); - throw new InsufficientNetworkCapacityException(msg, DataCenter.class, guestConfig.getDataCenterId()); + // allocate a load balancer device for the network + lbDeviceVO = allocateLoadBalancerForNetwork(guestConfig); + if (lbDeviceVO == null) { + String msg = "failed to alloacate a external load balancer for the network " + guestConfig.getId(); + s_logger.error(msg); + throw new InsufficientNetworkCapacityException(msg, DataCenter.class, guestConfig.getDataCenterId()); + } } externalLoadBalancer = _hostDao.findById(lbDeviceVO.getHostId()); s_logger.debug("Allocated external load balancer device:" + lbDeviceVO.getId() + " for the network: " + guestConfig.getId()); @@ -928,6 +979,12 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase Integer networkRate = _networkMgr.getNetworkRate(guestConfig.getId(), null); if (add) { + // on restart network, network could have already been implemented. If already implemented then return + NicVO selfipNic = getPlaceholderNic(guestConfig); + if (selfipNic != null) { + return true; + } + // Acquire a self-ip address from the guest network IP address range selfIp = _networkMgr.acquireGuestIpAddress(guestConfig, null); if (selfIp == null) { @@ -956,8 +1013,9 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase if (answer == null || !answer.getResult()) { String action = add ? "implement" : "shutdown"; - String answerDetails = (answer != null) ? answer.getDetails() : "answer was null"; - String msg = "External load balancer was unable to " + action + " the guest network on the external load balancer in zone " + zone.getName() + " due to " + answerDetails; + String answerDetails = (answer != null) ? answer.getDetails() : null; + answerDetails = (answerDetails != null) ? " due to " + answerDetails : ""; + String msg = "External load balancer was unable to " + action + " the guest network on the external load balancer in zone " + zone.getName() + answerDetails; s_logger.error(msg); throw new ResourceUnavailableException(msg, Network.class, guestConfig.getId()); } @@ -1029,4 +1087,25 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase return new DeleteHostAnswer(true); } + protected IpDeployer getIpDeployerForInlineMode(Network network) { + //We won't deploy IP, instead the firewall in front of us would do it + List providers = _networkMgr.getProvidersForServiceInNetwork(network, Service.Firewall); + //Only support one provider now + if (providers == null) { + s_logger.error("Cannot find firewall provider for network " + network.getId()); + return null; + } + if (providers.size() != 1) { + s_logger.error("Found " + providers.size() + " firewall provider for network " + network.getId()); + return null; + } + + NetworkElement element = _networkMgr.getElementImplementingProvider(providers.get(0).getName()); + if (!(element instanceof IpDeployer)) { + s_logger.error("The firewall provider for network " + network.getName() + " don't have ability to deploy IP address!"); + return null; + } + s_logger.info("Let " + element.getName() + " handle ip association for " + getName() + " in network " + network.getId()); + return (IpDeployer)element; + } } diff --git a/server/src/com/cloud/network/InlineLoadBalancerNicMapVO.java b/server/src/com/cloud/network/InlineLoadBalancerNicMapVO.java index ade6dae9bb6..56ac277d419 100644 --- a/server/src/com/cloud/network/InlineLoadBalancerNicMapVO.java +++ b/server/src/com/cloud/network/InlineLoadBalancerNicMapVO.java @@ -31,9 +31,6 @@ public class InlineLoadBalancerNicMapVO { @Column(name="id") private long id; - @Column(name="load_balancer_id") - private long loadBalancerId; - @Column(name="public_ip_address") private String publicIpAddress; @@ -42,8 +39,7 @@ public class InlineLoadBalancerNicMapVO { public InlineLoadBalancerNicMapVO() { } - public InlineLoadBalancerNicMapVO(long loadBalancerId, String publicIpAddress, long nicId) { - this.loadBalancerId = loadBalancerId; + public InlineLoadBalancerNicMapVO(String publicIpAddress, long nicId) { this.publicIpAddress = publicIpAddress; this.nicId = nicId; } @@ -52,10 +48,6 @@ public class InlineLoadBalancerNicMapVO { return id; } - public long getLoadBalancerId() { - return loadBalancerId; - } - public String getPublicIpAddress() { return publicIpAddress; } diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index d52e88a45bd..ef0d4c599df 100755 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -40,12 +40,15 @@ import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; import com.cloud.network.Networks.TrafficType; import com.cloud.network.addr.PublicIp; +import com.cloud.network.element.LoadBalancingServiceProvider; import com.cloud.network.element.NetworkElement; import com.cloud.network.element.RemoteAccessVPNServiceProvider; import com.cloud.network.element.Site2SiteVpnServiceProvider; +import com.cloud.network.element.StaticNatServiceProvider; import com.cloud.network.element.UserDataServiceProvider; import com.cloud.network.guru.NetworkGuru; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.StaticNat; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.NetworkOfferingVO; @@ -483,5 +486,12 @@ public interface NetworkManager extends NetworkService { */ int getNetworkLockTimeout(); + List getProvidersForServiceInNetwork(Network network, Service service); + + StaticNatServiceProvider getStaticNatProviderForNetwork(Network network); boolean isNetworkInlineMode(Network network); + + int getRuleCountForIp(Long addressId, FirewallRule.Purpose purpose, FirewallRule.State state); + + LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network); } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index f993b2b9b72..f7189df472a 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -732,6 +732,18 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag public boolean canIpsUseOffering(List publicIps, long offeringId) { Map> ipToServices = getIpToServices(publicIps, false, true); Map> serviceToProviders = getNetworkOfferingServiceProvidersMap(offeringId); + NetworkOfferingVO offering = _networkOfferingDao.findById(offeringId); + //For inline mode checking, using firewall provider for LB instead, because public ip would apply on firewall provider + if (offering.isInline()) { + Provider firewallProvider = null; + if (serviceToProviders.containsKey(Service.Firewall)) { + firewallProvider = (Provider)serviceToProviders.get(Service.Firewall).toArray()[0]; + } + Set p = new HashSet(); + p.add(firewallProvider); + serviceToProviders.remove(Service.Lb); + serviceToProviders.put(Service.Lb, p); + } for (PublicIp ip : ipToServices.keySet()) { Set services = ipToServices.get(ip); Provider provider = null; @@ -777,8 +789,17 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag throw new InvalidParameterException("There is no new provider for IP " + publicIp.getAddress() + " of service " + service.getName() + "!"); } Provider newProvider = (Provider) newProviders.toArray()[0]; - if (!oldProvider.equals(newProvider)) { - throw new InvalidParameterException("There would be multiple providers for IP " + publicIp.getAddress() + "!"); + Network network = _networksDao.findById(networkId); + NetworkElement oldElement = getElementImplementingProvider(oldProvider.getName()); + NetworkElement newElement = getElementImplementingProvider(newProvider.getName()); + if (oldElement instanceof IpDeployingRequester && newElement instanceof IpDeployingRequester) { + IpDeployer oldIpDeployer = ((IpDeployingRequester)oldElement).getIpDeployer(network); + IpDeployer newIpDeployer = ((IpDeployingRequester)newElement).getIpDeployer(network); + if (!oldIpDeployer.getProvider().getName().equals(newIpDeployer.getProvider().getName())) { + throw new InvalidParameterException("There would be multiple providers for IP " + publicIp.getAddress() + "!"); + } + } else { + throw new InvalidParameterException("Ip cannot be applied for new provider!"); } return true; } @@ -850,21 +871,17 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } 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 if (element instanceof ConnectivityProvider) { + if (element instanceof ConnectivityProvider) { // Nothing to do s_logger.debug("ConnectivityProvider " + element.getClass().getSimpleName() + " has no ip associations"); continue; - } else { + } + + if (!(element instanceof IpDeployingRequester)) { + throw new CloudRuntimeException("Element " + element + " is not a IpDeployingRequester!"); + } + deployer = ((IpDeployingRequester)element).getIpDeployer(network); + if (deployer == null) { throw new CloudRuntimeException("Fail to get ip deployer for element: " + element); } Set services = new HashSet(); @@ -3697,7 +3714,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } protected boolean deleteVlansInNetwork(long networkId, long userId, Account callerAccount) { - + //cleanup Public vlans List publicVlans = _vlanDao.listVlansByNetworkId(networkId); boolean result = true; @@ -3706,8 +3723,8 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag s_logger.warn("Failed to delete vlan " + vlan.getId() + ");"); result = false; } - } - + } + //cleanup private vlans int privateIpAllocCount = _privateIpDao.countAllocatedByNetworkId(networkId); if (privateIpAllocCount > 0) { @@ -3724,25 +3741,23 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag public boolean validateRule(FirewallRule rule) { Network network = _networksDao.findById(rule.getNetworkId()); Purpose purpose = rule.getPurpose(); - for (NetworkElement ne : _networkElements) { - boolean validated; - switch (purpose) { - case LoadBalancing: - if (!(ne instanceof LoadBalancingServiceProvider)) { - continue; - } - validated = ((LoadBalancingServiceProvider) ne).validateLBRule(network, (LoadBalancingRule) rule); - if (!validated) - return false; - break; - default: - s_logger.debug("Unable to validate network rules for purpose: " + purpose.toString()); - validated = false; + switch (purpose) { + case LoadBalancing: + LoadBalancingServiceProvider ne = getLoadBalancingProviderForNetwork(network); + if (!ne.validateLBRule(network, (LoadBalancingRule) rule)) { + return false; } + break; + default: + s_logger.debug("Unable to validate network rules for purpose: " + purpose.toString()); } return true; } + protected boolean applyLbRules(Network network, List rules, LoadBalancingServiceProvider element) throws ResourceUnavailableException { + return element.applyLBRules(network, rules); + } + @Override /* The rules here is only the same kind of rule, e.g. all load balancing rules or all port forwarding rules */ public boolean applyRules(List rules, boolean continueOnError) throws ResourceUnavailableException { @@ -3769,47 +3784,55 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag // the network so as to ensure IP is associated before applying rules (in add state) applyIpAssociations(network, false, continueOnError, publicIps); - for (NetworkElement ne : _networkElements) { - Provider provider = Network.Provider.getProvider(ne.getName()); - if (provider == null) { - if (ne.getName().equalsIgnoreCase("Ovs") || ne.getName().equalsIgnoreCase("BareMetal") - || ne.getName().equalsIgnoreCase("CiscoNexus1000vVSM")) { - continue; - } - throw new CloudRuntimeException("Unable to identify the provider by name " + ne.getName()); + Service service = null; + switch (purpose) { + case LoadBalancing: + service = Service.Lb; + break; + case PortForwarding: + service = Service.PortForwarding; + break; + case StaticNat: + case Firewall: + service = Service.Firewall; + break; + case NetworkACL: + service = Service.NetworkACL; + break; + default: + break; + } + + if (service != null) { + List providers = getProvidersForServiceInNetwork(network, service); + if (providers == null || providers.size() != 1) { + // FIXME: If there is a service not made available by network offering, then rule should not get created + // in first place. For now error out during the apply rules. + String msg = "Cannot find the " + service.getName() + " provider for network " + network.getId(); + s_logger.error(msg); + throw new CloudRuntimeException(msg); } + NetworkElement ne = getElementImplementingProvider(providers.get(0).getName()); try { boolean handled; switch (purpose) { case LoadBalancing: - boolean isLbProvider = isProviderSupportServiceInNetwork(network.getId(), Service.Lb, provider); - if (!(ne instanceof LoadBalancingServiceProvider && isLbProvider)) { - continue; - } - handled = ((LoadBalancingServiceProvider) ne).applyLBRules(network, (List) rules); + assert ne instanceof LoadBalancingServiceProvider; + handled = applyLbRules(network, (List)rules, (LoadBalancingServiceProvider) ne); break; case PortForwarding: - boolean isPfProvider = isProviderSupportServiceInNetwork(network.getId(), Service.PortForwarding, provider); - if (!(ne instanceof PortForwardingServiceProvider && isPfProvider)) { - continue; - } + assert ne instanceof PortForwardingServiceProvider; handled = ((PortForwardingServiceProvider) ne).applyPFRules(network, (List) rules); break; case StaticNat: /* It's firewall rule for static nat, not static nat rule */ /* Fall through */ case Firewall: - boolean isFirewallProvider = isProviderSupportServiceInNetwork(network.getId(), Service.Firewall, provider); - if (!(ne instanceof FirewallServiceProvider && isFirewallProvider)) { - continue; - } + assert ne instanceof FirewallServiceProvider; handled = ((FirewallServiceProvider) ne).applyFWRules(network, rules); break; case NetworkACL: - boolean isNetworkACLProvider = isProviderSupportServiceInNetwork(network.getId(), Service.NetworkACL, provider); - if (!(ne instanceof NetworkACLServiceProvider && isNetworkACLProvider)) { - continue; - } + assert ne instanceof NetworkACLServiceProvider; handled = ((NetworkACLServiceProvider) ne).applyNetworkACLs(network, rules); break; default: @@ -3824,6 +3847,9 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag s_logger.warn("Problems with " + ne.getName() + " but pushing on", e); success = false; } + } else { + s_logger.debug("Unable to handle network rules for purpose: " + purpose.toString()); + success = false; } // if all the rules configured on public IP are revoked then dis-associate IP with network service provider @@ -4398,6 +4424,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } + @Override public UserDataServiceProvider getPasswordResetProvider(Network network) { String passwordProvider = _ntwkSrvcDao.getProviderForServiceInNetwork(network.getId(), Service.UserData); @@ -4827,6 +4854,9 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag // log assign usage events for new offering List nics = _nicDao.listByNetworkId(networkId); for (NicVO nic : nics) { + if (nic.getReservationStrategy() == Nic.ReservationStrategy.PlaceHolder) { + continue; + } long vmId = nic.getInstanceId(); VMInstanceVO vm = _vmDao.findById(vmId); if (vm == null) { @@ -5043,23 +5073,15 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag applyIpAssociations(network, false, continueOnError, publicIps); // get provider - String staticNatProvider = _ntwkSrvcDao.getProviderForServiceInNetwork(network.getId(), Service.StaticNat); - - for (NetworkElement ne : _networkElements) { - try { - if (!(ne instanceof StaticNatServiceProvider && ne.getName().equalsIgnoreCase(staticNatProvider))) { - continue; - } - - boolean handled = ((StaticNatServiceProvider) ne).applyStaticNats(network, staticNats); - s_logger.debug("Static Nat for network " + network.getId() + " were " + (handled ? "" : " not") + " handled by " + ne.getName()); - } catch (ResourceUnavailableException e) { - if (!continueOnError) { - throw e; - } - s_logger.warn("Problems with " + ne.getName() + " but pushing on", e); - success = false; + StaticNatServiceProvider element = getStaticNatProviderForNetwork(network); + try { + success = element.applyStaticNats(network, staticNats); + } catch (ResourceUnavailableException e) { + if (!continueOnError) { + throw e; } + s_logger.warn("Problems with " + element.getName() + " but pushing on", e); + success = false; } // For revoked static nat IP, set the vm_id to null, indicate it should be revoked @@ -7485,8 +7507,55 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } @Override + public List getProvidersForServiceInNetwork(Network network, Service service) { + Map> service2ProviderMap = getServiceProvidersMap(network.getId()); + if (service2ProviderMap.get(service) != null) { + List providers = new ArrayList(service2ProviderMap.get(service)); + return providers; + } + return null; + } + + protected NetworkElement getElementForServiceInNetwork(Network network, Service service) { + List providers = getProvidersForServiceInNetwork(network, service); + //Only support one provider now + if (providers == null) { + s_logger.error("Cannot find " + service.getName() + " provider for network " + network.getId()); + return null; + } + if (providers.size() != 1) { + s_logger.error("Found " + providers.size() + " " + service.getName() + " providers for network!" + network.getId()); + return null; + } + NetworkElement element = getElementImplementingProvider(providers.get(0).getName()); + s_logger.info("Let " + element.getName() + " handle " + service.getName() + " in network " + network.getId()); + return element; + } + + @Override + public StaticNatServiceProvider getStaticNatProviderForNetwork(Network network) { + NetworkElement element = getElementForServiceInNetwork(network, Service.StaticNat); + assert element instanceof StaticNatServiceProvider; + return (StaticNatServiceProvider)element; + } + + @Override + public LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network) { + NetworkElement element = getElementForServiceInNetwork(network, Service.Lb); + assert element instanceof LoadBalancingServiceProvider; + return ( LoadBalancingServiceProvider)element; + } public boolean isNetworkInlineMode(Network network) { NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); return offering.isInline(); } + + @Override + public int getRuleCountForIp(Long addressId, FirewallRule.Purpose purpose, FirewallRule.State state) { + List rules = _firewallDao.listByIpAndPurposeWithState(addressId, purpose, state); + if (rules == null) { + return 0; + } + return rules.size(); + } } diff --git a/server/src/com/cloud/network/dao/FirewallRulesDao.java b/server/src/com/cloud/network/dao/FirewallRulesDao.java index 2a4c200f116..cc184c84fce 100644 --- a/server/src/com/cloud/network/dao/FirewallRulesDao.java +++ b/server/src/com/cloud/network/dao/FirewallRulesDao.java @@ -56,6 +56,6 @@ public interface FirewallRulesDao extends GenericDao { long countRulesByIpId(long sourceIpId); List listByNetworkPurposeTrafficTypeAndNotRevoked(long networkId, FirewallRule.Purpose purpose, FirewallRule.TrafficType trafficType); - - + + List listByIpAndPurposeWithState(Long addressId, FirewallRule.Purpose purpose, FirewallRule.State state); } diff --git a/server/src/com/cloud/network/dao/FirewallRulesDaoImpl.java b/server/src/com/cloud/network/dao/FirewallRulesDaoImpl.java index a2478d8d497..2fff15aff8d 100644 --- a/server/src/com/cloud/network/dao/FirewallRulesDaoImpl.java +++ b/server/src/com/cloud/network/dao/FirewallRulesDaoImpl.java @@ -309,4 +309,19 @@ public class FirewallRulesDaoImpl extends GenericDaoBase i return result; } + @Override + public List listByIpAndPurposeWithState(Long ipId, Purpose purpose, State state) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("ipId", ipId); + + if (state != null) { + sc.setParameters("state", state); + } + + if (purpose != null) { + sc.setParameters("purpose", purpose); + } + + return listBy(sc); + } } diff --git a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java index 6346bc3fd6a..60eb70f9882 100755 --- a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java +++ b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java @@ -579,8 +579,14 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa private boolean isRollBackAllowedForProvider(LoadBalancerVO loadBalancer) { Network network = _networkDao.findById(loadBalancer.getNetworkId()); - Provider provider = Network.Provider.Netscaler; - return _ntwkSrvcDao.canProviderSupportServiceInNetwork(network.getId(), Service.Lb, provider); + List provider = _networkMgr.getProvidersForServiceInNetwork(network, Service.Lb); + if (provider == null || provider.size() == 0) { + return false; + } + if (provider.get(0) == Provider.Netscaler || provider.get(0) == Provider.F5BigIp) { + return true; + } + return false; } @Override @DB @@ -1056,6 +1062,12 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa LoadBalancerVO newRule = new LoadBalancerVO(lb.getXid(), lb.getName(), lb.getDescription(), lb.getSourceIpAddressId(), lb.getSourcePortEnd(), lb.getDefaultPortStart(), lb.getAlgorithm(), network.getId(), ipAddr.getAllocatedToAccountId(), ipAddr.getAllocatedInDomainId()); + // verify rule is supported by Lb provider of the network + LoadBalancingRule loadBalancing = new LoadBalancingRule(newRule, new ArrayList(), new ArrayList()); + if (!_networkMgr.validateRule(loadBalancing)) { + throw new InvalidParameterValueException("LB service provider cannot support this rule"); + } + newRule = _lbDao.persist(newRule); if (openFirewall) { diff --git a/server/test/com/cloud/network/MockNetworkManagerImpl.java b/server/test/com/cloud/network/MockNetworkManagerImpl.java index d8ef9e4cfbe..0b83f351810 100755 --- a/server/test/com/cloud/network/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/network/MockNetworkManagerImpl.java @@ -35,12 +35,16 @@ import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; import com.cloud.network.Networks.TrafficType; import com.cloud.network.addr.PublicIp; +import com.cloud.network.element.LoadBalancingServiceProvider; import com.cloud.network.element.NetworkElement; import com.cloud.network.element.RemoteAccessVPNServiceProvider; import com.cloud.network.element.Site2SiteVpnServiceProvider; +import com.cloud.network.element.StaticNatServiceProvider; import com.cloud.network.element.UserDataServiceProvider; import com.cloud.network.guru.NetworkGuru; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.FirewallRule.Purpose; +import com.cloud.network.rules.FirewallRule.State; import com.cloud.network.rules.StaticNat; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.NetworkOfferingVO; @@ -1141,4 +1145,29 @@ public class MockNetworkManagerImpl implements NetworkManager, Manager, NetworkS // TODO Auto-generated method stub return false; } + + @Override + public StaticNatServiceProvider getStaticNatProviderForNetwork(Network network) { + // TODO Auto-generated method stub + return null; + } + + @Override + public List getProvidersForServiceInNetwork(Network network, + Service service) { + // TODO Auto-generated method stub + return null; + } + + @Override + public int getRuleCountForIp(Long addressId, Purpose purpose, State state) { + // TODO Auto-generated method stub + return 0; + } + + @Override + public LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network) { + // TODO Auto-generated method stub + return null; + } } diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java index 2141c1b0e09..824e40d6b14 100644 --- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java @@ -37,12 +37,16 @@ import com.cloud.network.Network.Service; import com.cloud.network.Networks.TrafficType; import com.cloud.network.addr.PublicIp; import com.cloud.network.dao.NetworkServiceMapDao; +import com.cloud.network.element.LoadBalancingServiceProvider; import com.cloud.network.element.NetworkElement; import com.cloud.network.element.RemoteAccessVPNServiceProvider; import com.cloud.network.element.Site2SiteVpnServiceProvider; +import com.cloud.network.element.StaticNatServiceProvider; import com.cloud.network.element.UserDataServiceProvider; import com.cloud.network.guru.NetworkGuru; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.FirewallRule.Purpose; +import com.cloud.network.rules.FirewallRule.State; import com.cloud.network.rules.StaticNat; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.NetworkOfferingVO; @@ -1485,4 +1489,28 @@ public class MockNetworkManagerImpl implements NetworkManager, Manager{ // TODO Auto-generated method stub return false; } + + @Override + public List getProvidersForServiceInNetwork(Network network, Service service) { + // TODO Auto-generated method stub + return null; + } + + @Override + public StaticNatServiceProvider getStaticNatProviderForNetwork(Network network) { + // TODO Auto-generated method stub + return null; + } + + @Override + public int getRuleCountForIp(Long addressId, Purpose purpose, State state) { + // TODO Auto-generated method stub + return 0; + } + + @Override + public LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network) { + // TODO Auto-generated method stub + return null; + } } diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index fb00ed4cd37..b37c3f04517 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -746,12 +746,10 @@ CREATE TABLE `cloud`.`load_balancer_stickiness_policies` ( CREATE TABLE `cloud`.`inline_load_balancer_nic_map` ( `id` bigint unsigned NOT NULL auto_increment, - `load_balancer_id` bigint unsigned NOT NULL, `public_ip_address` char(40) NOT NULL, `nic_id` bigint unsigned NULL COMMENT 'nic id', PRIMARY KEY (`id`), UNIQUE KEY (`nic_id`), - CONSTRAINT `fk_inline_load_balancer_nic_map__load_balancer_id` FOREIGN KEY(`load_balancer_id`) REFERENCES `load_balancing_rules`(`id`) ON DELETE CASCADE, CONSTRAINT `fk_inline_load_balancer_nic_map__nic_id` FOREIGN KEY(`nic_id`) REFERENCES `nics`(`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/setup/db/db/schema-40to410.sql b/setup/db/db/schema-40to410.sql index 2ce86e0b894..5245a4939a0 100644 --- a/setup/db/db/schema-40to410.sql +++ b/setup/db/db/schema-40to410.sql @@ -68,3 +68,7 @@ ALTER TABLE `sync_queue` ADD `queue_size` SMALLINT NOT NULL DEFAULT '0' COMMENT ALTER TABLE `sync_queue` ADD `queue_size_limit` SMALLINT NOT NULL DEFAULT '1' COMMENT 'max number of items the queue can process concurrently'; ALTER TABLE `sync_queue_item` ADD `queue_proc_time` DATETIME NOT NULL COMMENT 'when processing started for the item' AFTER `queue_proc_number`; + +ALTER TABLE `cloud`.`inline_load_balancer_nic_map` DROP FOREIGN KEY fk_inline_load_balancer_nic_map__load_balancer_id; + +ALTER TABLE `cloud`.`inline_load_balancer_nic_map` DROP COLUMN load_balancer_id; From 51502e9f0615a048082d408b5b812899fa774b1d Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Fri, 4 Jan 2013 19:52:21 -0800 Subject: [PATCH 4/5] Fix license issue of new added xml files --- .../juniper/firewall-filter-term-add.xml | 18 ++++++++++++++++++ .../juniper/firewall-filter-term-getone.xml | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/scripts/network/juniper/firewall-filter-term-add.xml b/scripts/network/juniper/firewall-filter-term-add.xml index 4f96ed4d16e..e7f3a63f8e8 100644 --- a/scripts/network/juniper/firewall-filter-term-add.xml +++ b/scripts/network/juniper/firewall-filter-term-add.xml @@ -1,3 +1,21 @@ + diff --git a/scripts/network/juniper/firewall-filter-term-getone.xml b/scripts/network/juniper/firewall-filter-term-getone.xml index 782290992c1..2c7e10dd354 100644 --- a/scripts/network/juniper/firewall-filter-term-getone.xml +++ b/scripts/network/juniper/firewall-filter-term-getone.xml @@ -1,3 +1,21 @@ + From 3d9dc36463280afeee178cca78ef41560b6e3027 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Fri, 4 Jan 2013 20:03:16 -0800 Subject: [PATCH 5/5] The other xml license fix --- scripts/network/juniper/template-entry.xml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/scripts/network/juniper/template-entry.xml b/scripts/network/juniper/template-entry.xml index cf0cb6c37e3..ab92d6d7d7d 100644 --- a/scripts/network/juniper/template-entry.xml +++ b/scripts/network/juniper/template-entry.xml @@ -1,3 +1,21 @@ + <%name%> %value%