From 278f2a401f677d2551004d3b027e6c994165b33a Mon Sep 17 00:00:00 2001 From: alena Date: Thu, 11 Aug 2011 10:14:23 -0700 Subject: [PATCH] bug 10561: intermediate checkin for enable/disableStaticNat. 1) On enableStaticNat command we actually send the command to the backend (we used to just upgrade the DB in the past). The backend command carries sourceIp and destIp, and creates IP to IP mapping on the domR. 2) On disableStaticNat for the Ip address in addition to cleaning up port ranges, we also delete IP to IP mapping on the domR. --- .../api/routing/SetStaticNatRulesAnswer.java | 4 +- .../cloud/agent/api/to/StaticNatRuleTO.java | 4 +- .../api/commands/DisableStaticNatCmd.java | 2 +- .../api/commands/EnableStaticNatCmd.java | 2 +- .../cloud/network/element/NetworkElement.java | 10 +++ .../com/cloud/network/rules/RulesService.java | 4 +- .../com/cloud/network/rules/StaticNat.java | 35 +++++++++ .../VirtualRoutingResource.java | 10 ++- .../xen/resource/CitrixResourceBase.java | 15 +++- .../src/com/cloud/network/NetworkManager.java | 3 + .../com/cloud/network/NetworkManagerImpl.java | 26 +++++++ .../cloud/network/element/DhcpElement.java | 6 ++ .../element/ElasticLoadBalancerElement.java | 6 ++ .../com/cloud/network/element/OvsElement.java | 6 ++ .../network/element/VirtualRouterElement.java | 18 +++++ .../network/firewall/FirewallManagerImpl.java | 2 +- .../VirtualNetworkApplianceManager.java | 4 + .../VirtualNetworkApplianceManagerImpl.java | 63 +++++++++++++++- .../com/cloud/network/rules/RulesManager.java | 2 + .../cloud/network/rules/RulesManagerImpl.java | 73 ++++++++++++++++++- .../cloud/network/rules/StaticNatImpl.java | 71 ++++++++++++++++++ .../src/com/cloud/vm/UserVmManagerImpl.java | 2 +- 22 files changed, 347 insertions(+), 21 deletions(-) create mode 100644 api/src/com/cloud/network/rules/StaticNat.java create mode 100644 server/src/com/cloud/network/rules/StaticNatImpl.java diff --git a/api/src/com/cloud/agent/api/routing/SetStaticNatRulesAnswer.java b/api/src/com/cloud/agent/api/routing/SetStaticNatRulesAnswer.java index d7942e0cf7a..f393e8d31de 100644 --- a/api/src/com/cloud/agent/api/routing/SetStaticNatRulesAnswer.java +++ b/api/src/com/cloud/agent/api/routing/SetStaticNatRulesAnswer.java @@ -25,8 +25,8 @@ public class SetStaticNatRulesAnswer extends Answer { super(); } - public SetStaticNatRulesAnswer(SetStaticNatRulesCommand cmd, String[] results) { - super(cmd, true, null); + public SetStaticNatRulesAnswer(SetStaticNatRulesCommand cmd, String[] results, Boolean success) { + super(cmd, success, null); assert(cmd.getRules().length == results.length) : "Shouldn't the results match the commands?"; this.results = results; diff --git a/api/src/com/cloud/agent/api/to/StaticNatRuleTO.java b/api/src/com/cloud/agent/api/to/StaticNatRuleTO.java index c0359dbb0d7..a4845989d7f 100644 --- a/api/src/com/cloud/agent/api/to/StaticNatRuleTO.java +++ b/api/src/com/cloud/agent/api/to/StaticNatRuleTO.java @@ -41,8 +41,8 @@ public class StaticNatRuleTO extends FirewallRuleTO{ } - protected StaticNatRuleTO(long id, String srcIp, int srcPortStart, int srcPortEnd, String dstIp, int dstPortStart, int dstPortEnd, String protocol, boolean revoked, boolean brandNew) { - super(id, srcIp, protocol, srcPortStart, srcPortEnd, revoked, brandNew, FirewallRule.Purpose.StaticNat, null,0,0); + public StaticNatRuleTO(long id, String srcIp, Integer srcPortStart, Integer srcPortEnd, String dstIp, Integer dstPortStart, Integer dstPortEnd, String protocol, boolean revoked, boolean alreadyAdded) { + super(id, srcIp, protocol, srcPortStart, srcPortEnd, revoked, alreadyAdded, FirewallRule.Purpose.StaticNat, null,0,0); this.dstIp = dstIp; } diff --git a/api/src/com/cloud/api/commands/DisableStaticNatCmd.java b/api/src/com/cloud/api/commands/DisableStaticNatCmd.java index 258cbd6b021..afc68cd7d66 100644 --- a/api/src/com/cloud/api/commands/DisableStaticNatCmd.java +++ b/api/src/com/cloud/api/commands/DisableStaticNatCmd.java @@ -76,7 +76,7 @@ public class DisableStaticNatCmd extends BaseAsyncCmd { @Override public void execute() throws ResourceUnavailableException { - boolean result = _rulesService.disableOneToOneNat(ipAddressId); + boolean result = _rulesService.disableStaticNat(ipAddressId); if (result) { SuccessResponse response = new SuccessResponse(getCommandName()); diff --git a/api/src/com/cloud/api/commands/EnableStaticNatCmd.java b/api/src/com/cloud/api/commands/EnableStaticNatCmd.java index 3b6262b8259..e8f1879e7ab 100644 --- a/api/src/com/cloud/api/commands/EnableStaticNatCmd.java +++ b/api/src/com/cloud/api/commands/EnableStaticNatCmd.java @@ -80,7 +80,7 @@ public class EnableStaticNatCmd extends BaseCmd{ @Override public void execute(){ try { - boolean result = _rulesService.enableOneToOneNat(ipAddressId, virtualMachineId); + boolean result = _rulesService.enableStaticNat(ipAddressId, virtualMachineId); if (result) { SuccessResponse response = new SuccessResponse(getCommandName()); this.setResponseObject(response); diff --git a/api/src/com/cloud/network/element/NetworkElement.java b/api/src/com/cloud/network/element/NetworkElement.java index c14b06db9b6..a4f42dffd9d 100644 --- a/api/src/com/cloud/network/element/NetworkElement.java +++ b/api/src/com/cloud/network/element/NetworkElement.java @@ -35,6 +35,7 @@ import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; import com.cloud.network.PublicIpAddress; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.StaticNat; import com.cloud.offering.NetworkOffering; import com.cloud.utils.component.Adapter; import com.cloud.vm.NicProfile; @@ -132,5 +133,14 @@ public interface NetworkElement extends Adapter { * @throws ResourceUnavailableException */ boolean applyRules(Network network, List rules) throws ResourceUnavailableException; + + /** + * Creates static nat rule (public IP to private IP mapping) on the network element + * @param config + * @param rules + * @return + * @throws ResourceUnavailableException + */ + boolean applyStaticNats(Network config, List rules) throws ResourceUnavailableException; } diff --git a/api/src/com/cloud/network/rules/RulesService.java b/api/src/com/cloud/network/rules/RulesService.java index 7af02a291fd..61e912ae5e0 100644 --- a/api/src/com/cloud/network/rules/RulesService.java +++ b/api/src/com/cloud/network/rules/RulesService.java @@ -54,9 +54,9 @@ public interface RulesService { boolean applyPortForwardingRules(long ipAdddressId, Account caller) throws ResourceUnavailableException; - boolean enableOneToOneNat(long ipAddressId, long vmId) throws NetworkRuleConflictException; + boolean enableStaticNat(long ipAddressId, long vmId) throws NetworkRuleConflictException; - boolean disableOneToOneNat(long ipAddressId) throws ResourceUnavailableException; + boolean disableStaticNat(long ipAddressId) throws ResourceUnavailableException; PortForwardingRule getPortForwardigRule(long ruleId); FirewallRule getFirewallRule(long ruleId); diff --git a/api/src/com/cloud/network/rules/StaticNat.java b/api/src/com/cloud/network/rules/StaticNat.java new file mode 100644 index 00000000000..430eaf42094 --- /dev/null +++ b/api/src/com/cloud/network/rules/StaticNat.java @@ -0,0 +1,35 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.cloud.network.rules; + + +public interface StaticNat{ + + long getAccountId(); + + long getDomainId(); + + long getNetworkId(); + + long getSourceIpAddressId(); + + String getDestIpAddress(); + + boolean isForRevoke(); +} diff --git a/core/src/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java b/core/src/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java index f8ff6766ecb..d51ca001c1e 100755 --- a/core/src/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java +++ b/core/src/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java @@ -193,6 +193,7 @@ public class VirtualRoutingResource implements Manager { String routerIp = cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP); String[] results = new String[cmd.getRules().length]; int i = 0; + boolean endResult = true; for (StaticNatRuleTO rule : cmd.getRules()) { String result = null; final Script command = new Script(_firewallPath, _timeout, s_logger); @@ -207,10 +208,15 @@ public class VirtualRoutingResource implements Manager { command.add(" -G ") ; result = command.execute(); - results[i++] = (!(result == null || result.isEmpty())) ? "Failed" : null; + if (result == null || result.isEmpty()) { + results[i++] = "Failed"; + endResult = false; + } else { + results[i++] = null; + } } - return new SetStaticNatRulesAnswer(cmd, results); + return new SetStaticNatRulesAnswer(cmd, results, endResult); } diff --git a/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index 0a720014021..a5fcc203484 100644 --- a/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java +++ b/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java @@ -1269,6 +1269,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe //String args = routerIp; String[] results = new String[cmd.getRules().length]; int i = 0; + boolean endResult = true; for (StaticNatRuleTO rule : cmd.getRules()) { //1:1 NAT needs instanceip;publicip;domrip;op StringBuilder args = new StringBuilder(); @@ -1276,15 +1277,23 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe args.append(rule.revoked() ? " -D " : " -A "); args.append(" -l ").append(rule.getSrcIp()); args.append(" -r ").append(rule.getDstIp()); - args.append(" -P ").append(rule.getProtocol().toLowerCase()); + if (rule.getProtocol() != null) { + args.append(" -P ").append(rule.getProtocol().toLowerCase()); + } + args.append(" -d ").append(rule.getStringSrcPortRange()); args.append(" -G "); String result = callHostPlugin(conn, "vmops", "setFirewallRule", "args", args.toString()); - results[i++] = (result == null || result.isEmpty()) ? "Failed" : null; + if (result == null || result.isEmpty()) { + results[i++] = "Failed"; + endResult = false; + } else { + results[i++] = null; + } } - return new SetStaticNatRulesAnswer(cmd, results); + return new SetStaticNatRulesAnswer(cmd, results, endResult); } protected Answer execute(final LoadBalancerConfigCommand cmd) { diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index c46f2b6728e..163c428cc10 100644 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -35,6 +35,7 @@ import com.cloud.network.Networks.TrafficType; import com.cloud.network.addr.PublicIp; import com.cloud.network.guru.NetworkGuru; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.StaticNat; import com.cloud.network.vpn.PasswordResetElement; import com.cloud.network.vpn.RemoteAccessVpnElement; import com.cloud.offerings.NetworkOfferingVO; @@ -210,4 +211,6 @@ public interface NetworkManager extends NetworkService { String getGlobalGuestDomainSuffix(); String getStartIpAddress(long networkId); + + boolean applyStaticNats(List staticNats, boolean continueOnError) throws ResourceUnavailableException; } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index e30225f3a69..3cb30dea9af 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -102,6 +102,7 @@ import com.cloud.network.guru.NetworkGuru; import com.cloud.network.lb.LoadBalancingRulesManager; import com.cloud.network.rules.FirewallManager; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.StaticNat; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.RulesManager; @@ -3190,4 +3191,29 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag return startIP; } + + @Override + public boolean applyStaticNats(List staticNats, boolean continueOnError) throws ResourceUnavailableException { + if (staticNats == null || staticNats.size() == 0) { + s_logger.debug("There are no static nat rules for the network elements"); + return true; + } + + boolean success = true; + Network network = _networksDao.findById(staticNats.get(0).getNetworkId()); + for (NetworkElement ne : _networkElements) { + try { + boolean handled = 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; + } + } + + return success; + } } diff --git a/server/src/com/cloud/network/element/DhcpElement.java b/server/src/com/cloud/network/element/DhcpElement.java index 97dff205318..42efc838cad 100644 --- a/server/src/com/cloud/network/element/DhcpElement.java +++ b/server/src/com/cloud/network/element/DhcpElement.java @@ -45,6 +45,7 @@ import com.cloud.network.dao.NetworkDao; import com.cloud.network.router.VirtualNetworkApplianceManager; import com.cloud.network.router.VirtualRouter; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.StaticNat; import com.cloud.network.vpn.PasswordResetElement; import com.cloud.offering.NetworkOffering; import com.cloud.user.AccountManager; @@ -245,4 +246,9 @@ public class DhcpElement extends AdapterBase implements NetworkElement, Password return _routerMgr.savePasswordToRouter(network, nic, uservm); } + + @Override + public boolean applyStaticNats(Network config, List rules) throws ResourceUnavailableException { + return false; + } } diff --git a/server/src/com/cloud/network/element/ElasticLoadBalancerElement.java b/server/src/com/cloud/network/element/ElasticLoadBalancerElement.java index 63824448330..c096325814d 100644 --- a/server/src/com/cloud/network/element/ElasticLoadBalancerElement.java +++ b/server/src/com/cloud/network/element/ElasticLoadBalancerElement.java @@ -42,6 +42,7 @@ import com.cloud.network.PublicIpAddress; import com.cloud.network.dao.NetworkDao; import com.cloud.network.lb.ElasticLoadBalancerManager; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.StaticNat; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.utils.component.AdapterBase; @@ -166,4 +167,9 @@ public class ElasticLoadBalancerElement extends AdapterBase implements NetworkEl } return true; } + + @Override + public boolean applyStaticNats(Network config, List rules) throws ResourceUnavailableException { + return false; + } } diff --git a/server/src/com/cloud/network/element/OvsElement.java b/server/src/com/cloud/network/element/OvsElement.java index ed51c0291bc..4cfe1ef50e2 100644 --- a/server/src/com/cloud/network/element/OvsElement.java +++ b/server/src/com/cloud/network/element/OvsElement.java @@ -38,6 +38,7 @@ import com.cloud.network.element.NetworkElement; import com.cloud.network.ovs.OvsNetworkManager; import com.cloud.network.ovs.OvsTunnelManager; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.StaticNat; import com.cloud.offering.NetworkOffering; import com.cloud.utils.component.AdapterBase; import com.cloud.utils.component.Inject; @@ -142,5 +143,10 @@ public class OvsElement extends AdapterBase implements NetworkElement { throws ConcurrentOperationException, ResourceUnavailableException { return true; } + + @Override + public boolean applyStaticNats(Network config, List rules) throws ResourceUnavailableException { + return false; + } } diff --git a/server/src/com/cloud/network/element/VirtualRouterElement.java b/server/src/com/cloud/network/element/VirtualRouterElement.java index d4bfa290c99..f7fe4354b53 100644 --- a/server/src/com/cloud/network/element/VirtualRouterElement.java +++ b/server/src/com/cloud/network/element/VirtualRouterElement.java @@ -49,6 +49,7 @@ import com.cloud.network.router.VirtualNetworkApplianceManager; import com.cloud.network.router.VirtualRouter; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.RulesManager; +import com.cloud.network.rules.StaticNat; import com.cloud.network.vpn.RemoteAccessVpnElement; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.dao.NetworkOfferingDao; @@ -284,4 +285,21 @@ public class VirtualRouterElement extends DhcpElement implements NetworkElement, return capabilities; } + + @Override + public boolean applyStaticNats(Network config, List rules) throws ResourceUnavailableException { + DataCenter dc = _configMgr.getZone(config.getDataCenterId()); + if (canHandle(config.getGuestType(),dc)) { + long networkId = config.getId(); + List routers = _routerDao.findByNetwork(networkId); + if (routers == null || routers.isEmpty()) { + s_logger.debug("Virtual router elemnt doesn't need to apply static nat on the backend; virtual router doesn't exist in the network " + config.getId()); + return true; + } + + return _routerMgr.applyStaticNats(config, rules); + } else { + return true; + } + } } diff --git a/server/src/com/cloud/network/firewall/FirewallManagerImpl.java b/server/src/com/cloud/network/firewall/FirewallManagerImpl.java index ea9712e33cb..d6105b65d79 100644 --- a/server/src/com/cloud/network/firewall/FirewallManagerImpl.java +++ b/server/src/com/cloud/network/firewall/FirewallManagerImpl.java @@ -317,7 +317,6 @@ public class FirewallManagerImpl implements FirewallService, FirewallManager, Ma throw new InvalidParameterValueException("Protocol " + proto + " is currently supported only for rules with purpose " + Purpose.Firewall); } } - } @Override @@ -516,4 +515,5 @@ public class FirewallManagerImpl implements FirewallService, FirewallManager, Ma return rules.size() == 0; } + } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java index 2fc0902d21f..dbae1f1e4a3 100644 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java @@ -30,6 +30,7 @@ import com.cloud.network.RemoteAccessVpn; import com.cloud.network.VirtualNetworkApplianceService; import com.cloud.network.VpnUser; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.StaticNat; import com.cloud.user.Account; import com.cloud.user.User; import com.cloud.uservm.UserVm; @@ -89,4 +90,7 @@ public interface VirtualNetworkApplianceManager extends Manager, VirtualNetworkA VirtualRouter stop(VirtualRouter router, boolean forced, User callingUser, Account callingAccount) throws ConcurrentOperationException, ResourceUnavailableException; String getDnsBasicZoneUpdate(); + + boolean applyStaticNats(Network network, List rules) throws ResourceUnavailableException; + } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index bf60675a1ee..90a40472733 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -135,6 +135,7 @@ import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.PortForwardingRule; import com.cloud.network.rules.RulesManager; +import com.cloud.network.rules.StaticNat; import com.cloud.network.rules.StaticNatRule; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.offering.NetworkOffering; @@ -2087,8 +2088,8 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian public boolean applyFirewallRules(Network network, List rules) throws ResourceUnavailableException { List routers = _routerDao.findByNetwork(network.getId()); if (routers == null || routers.isEmpty()) { - s_logger.warn("Unable to apply lb rules, virtual router doesn't exist in the network " + network.getId()); - throw new ResourceUnavailableException("Unable to apply lb rules", DataCenter.class, network.getDataCenterId()); + s_logger.warn("Unable to apply firewall rules, virtual router doesn't exist in the network " + network.getId()); + throw new ResourceUnavailableException("Unable to apply firewall rules", DataCenter.class, network.getDataCenterId()); } boolean result = true; @@ -2197,4 +2198,62 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian return _dnsBasicZoneUpdates; } + + @Override + public boolean applyStaticNats(Network network, List rules) throws ResourceUnavailableException { + List routers = _routerDao.findByNetwork(network.getId()); + if (routers == null || routers.isEmpty()) { + s_logger.warn("Unable to create static nat, virtual router doesn't exist in the network " + network.getId()); + throw new ResourceUnavailableException("Unable to create static nat", DataCenter.class, network.getDataCenterId()); + } + + boolean result = true; + for (DomainRouterVO router : routers) { + if (router.getState() == State.Running) { + s_logger.debug("Applying " + rules.size() + " static nat in network " + network); + result = applyStaticNat(router, rules); + + //If rules fail to apply on one domR, no need to proceed with the rest + if (!result) { + throw new ResourceUnavailableException("Unable to apply static nat on router ", VirtualRouter.class, router.getId()); + } + + } else if (router.getState() == State.Stopped || router.getState() == State.Stopping) { + s_logger.debug("Router is in " + router.getState() + ", so not sending apply firewall rules commands to the backend"); + } else { + s_logger.warn("Unable to apply static nat, virtual router is not in the right state " + router.getState()); + throw new ResourceUnavailableException("Unable to apply static nat, virtual router is not in the right state", VirtualRouter.class, router.getId()); + } + } + + return result; + } + + + protected boolean applyStaticNat(DomainRouterVO router, List rules) throws ResourceUnavailableException { + Commands cmds = new Commands(OnError.Continue); + createApplyStaticNatCommands(rules, router, cmds); + // Send commands to router + return sendCommandsToRouter(router, cmds); + } + + private void createApplyStaticNatCommands(List rules, DomainRouterVO router, Commands cmds) { + List rulesTO = null; + if (rules != null) { + rulesTO = new ArrayList(); + for (StaticNat rule : rules) { + IpAddress sourceIp = _networkMgr.getIp(rule.getSourceIpAddressId()); + StaticNatRuleTO ruleTO = new StaticNatRuleTO(0, sourceIp.getAddress().addr(), null, null, rule.getDestIpAddress(), null, null, null, rule.isForRevoke(), false); + rulesTO.add(ruleTO); + } + } + + SetStaticNatRulesCommand cmd = new SetStaticNatRulesCommand(rulesTO); + cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, router.getPrivateIpAddress()); + cmd.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, router.getGuestIpAddress()); + cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName()); + DataCenterVO dcVo = _dcDao.findById(router.getDataCenterIdToDeployIn()); + cmd.setAccessDetail(NetworkElementCommand.ZONE_NETWORK_TYPE, dcVo.getNetworkType().toString()); + cmds.addCommand(cmd); + } } diff --git a/server/src/com/cloud/network/rules/RulesManager.java b/server/src/com/cloud/network/rules/RulesManager.java index 8872d2c1b95..1f83b1ca320 100644 --- a/server/src/com/cloud/network/rules/RulesManager.java +++ b/server/src/com/cloud/network/rules/RulesManager.java @@ -66,6 +66,8 @@ public interface RulesManager extends RulesService { boolean releasePorts(long ipId, String protocol, FirewallRule.Purpose purpose, int... ports); List listByNetworkId(long networkId); + + boolean applyStaticNat(long sourceIpId, boolean continueOnError, Account caller, boolean forRevoke); } diff --git a/server/src/com/cloud/network/rules/RulesManagerImpl.java b/server/src/com/cloud/network/rules/RulesManagerImpl.java index 972d7816e51..d1130dad42b 100755 --- a/server/src/com/cloud/network/rules/RulesManagerImpl.java +++ b/server/src/com/cloud/network/rules/RulesManagerImpl.java @@ -291,7 +291,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { } @Override - public boolean enableOneToOneNat(long ipId, long vmId) throws NetworkRuleConflictException { + public boolean enableStaticNat(long ipId, long vmId) throws NetworkRuleConflictException { Account caller = UserContext.current().getCaller(); @@ -351,7 +351,22 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { ipAddress.setOneToOneNat(true); ipAddress.setAssociatedWithVmId(vmId); - return _ipAddressDao.update(ipAddress.getId(), ipAddress); + if (_ipAddressDao.update(ipAddress.getId(), ipAddress)) { + //enable static nat on the backend + s_logger.trace("Enabling static nat for ip address " + ipAddress + " and vm id=" + vmId + " on the backend"); + if (applyStaticNat(ipId, false, caller, false)) { + return true; + } else { + ipAddress.setOneToOneNat(false); + ipAddress.setAssociatedWithVmId(null); + _ipAddressDao.update(ipAddress.getId(), ipAddress); + s_logger.warn("Failed to enable static nat rule for ip address " + ipId + " on the backend"); + return false; + } + } else { + s_logger.warn("Failed to update ip address " + ipAddress + " in the DB as a part of enableStaticNat"); + return false; + } } @@ -797,10 +812,14 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { s_logger.debug("Releasing " + staticNatRules.size() + " static nat rules for ip id=" + ipId); } + for (FirewallRuleVO rule : staticNatRules) { // Mark all static nat rules as Revoke, but don't revoke them yet revokeStaticNatRuleInternal(rule.getId(), caller, userId, false); } + + //revoke static nat for the ip address + boolean staticNatRevoked = applyStaticNat(ipId, false, caller, true); // revoke all port forwarding rules applyPortForwardingRules(ipId, true, caller); @@ -816,7 +835,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { s_logger.debug("Successfully released rules for ip id=" + ipId + " and # of rules now = " + rules.size()); } - return rules.size() == 0; + return (rules.size() == 0 && staticNatRevoked); } @Override @@ -955,7 +974,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { } @Override - public boolean disableOneToOneNat(long ipId) throws ResourceUnavailableException { + public boolean disableStaticNat(long ipId) throws ResourceUnavailableException { boolean success = true; Account caller = UserContext.current().getCaller(); @@ -1007,4 +1026,50 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { return new StaticNatRuleImpl(ruleVO, guestNic.getIp4Address()); } + @Override + public boolean applyStaticNat(long sourceIpId, boolean continueOnError, Account caller, boolean forRevoke) { + + List staticNats = new ArrayList(); + IpAddress sourceIp = _ipAddressDao.findById(sourceIpId); + + Long networkId = sourceIp.getAssociatedWithNetworkId(); + if (networkId == null) { + throw new CloudRuntimeException("Ip address is not associated with any network"); + } + + UserVmVO vm = _vmDao.findById(sourceIp.getAssociatedWithVmId()); + Network network = _networkMgr.getNetwork(networkId); + if (network == null) { + throw new CloudRuntimeException("Unable to find ip address to map to in vm id=" + vm.getId()); + } + + if (!sourceIp.isOneToOneNat()) { + s_logger.debug("Source ip id=" + sourceIpId + " is not one to one nat"); + return true; + } + + if (caller != null) { + _accountMgr.checkAccess(caller, sourceIp); + } + + //create new static nat rule + // Get nic IP4 address + Nic guestNic = _networkMgr.getNicInNetwork(sourceIp.getAssociatedWithVmId(), networkId); + assert (guestNic != null && guestNic.getIp4Address() != null) : "Vm doesn't belong to network associated with ipAddress or ip4 address is null...how is it possible?"; + String dstIp = guestNic.getIp4Address(); + StaticNatImpl staticNat = new StaticNatImpl(sourceIp.getAccountId(), sourceIp.getDomainId(), networkId, sourceIpId, dstIp, forRevoke); + staticNats.add(staticNat); + + try { + if (!_networkMgr.applyStaticNats(staticNats, continueOnError)) { + return false; + } + } catch (ResourceUnavailableException ex) { + s_logger.warn("Failed to create static nat rule due to ", ex); + return false; + } + + return true; + } + } diff --git a/server/src/com/cloud/network/rules/StaticNatImpl.java b/server/src/com/cloud/network/rules/StaticNatImpl.java new file mode 100644 index 00000000000..b8ebf2a002e --- /dev/null +++ b/server/src/com/cloud/network/rules/StaticNatImpl.java @@ -0,0 +1,71 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.cloud.network.rules; + +public class StaticNatImpl implements StaticNat{ + long accountId; + long domainId; + long networkId; + long sourceIpAddressId; + String destIpAddress; + boolean forRevoke; + + + + public StaticNatImpl(long accountId, long domainId, long networkId, long sourceIpAddressId, String destIpAddress, boolean forRevoke) { + super(); + this.accountId = accountId; + this.domainId = domainId; + this.networkId = networkId; + this.sourceIpAddressId = sourceIpAddressId; + this.destIpAddress = destIpAddress; + this.forRevoke = forRevoke; + } + + @Override + public long getAccountId() { + return accountId; + } + + @Override + public long getDomainId() { + return domainId; + } + + @Override + public long getNetworkId() { + return networkId; + } + + @Override + public long getSourceIpAddressId() { + return sourceIpAddressId; + } + + @Override + public String getDestIpAddress() { + return destIpAddress; + } + + @Override + public boolean isForRevoke() { + return forRevoke; + } + +} diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index a9cd7c16841..9866e252e80 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -1254,7 +1254,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager IPAddressVO ip = _ipAddressDao.findByAssociatedVmId(vmId); try { if (ip != null) { - if (_rulesMgr.disableOneToOneNat(ip.getId())) { + if (_rulesMgr.disableStaticNat(ip.getId())) { s_logger.debug("Disabled 1-1 nat for ip address " + ip + " as a part of vm id=" + vmId + " expunge"); } else { s_logger.warn("Failed to disable static nat for ip address " + ip + " as a part of vm id=" + vmId + " expunge");