diff --git a/api/src/com/cloud/api/commands/CreateIpForwardingRuleCmd.java b/api/src/com/cloud/api/commands/CreateIpForwardingRuleCmd.java
index 7350a3ef052..81d40d01680 100644
--- a/api/src/com/cloud/api/commands/CreateIpForwardingRuleCmd.java
+++ b/api/src/com/cloud/api/commands/CreateIpForwardingRuleCmd.java
@@ -28,7 +28,9 @@ import com.cloud.api.Parameter;
import com.cloud.api.ServerApiException;
import com.cloud.api.response.FirewallRuleResponse;
import com.cloud.event.EventTypes;
+import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.network.IpAddress;
import com.cloud.network.rules.PortForwardingRule;
import com.cloud.user.Account;
import com.cloud.user.UserContext;
@@ -46,9 +48,6 @@ public class CreateIpForwardingRuleCmd extends BaseAsyncCreateCmd implements Por
@Parameter(name=ApiConstants.IP_ADDRESS, type=CommandType.STRING, required=true, description="the public IP address of the forwarding rule, already associated via associateIp")
private String ipAddress;
-
- @Parameter(name=ApiConstants.VIRTUAL_MACHINE_ID, type=CommandType.LONG, required=true, description="the ID of the virtual machine for the forwarding rule")
- private Long virtualMachineId;
@Parameter(name=ApiConstants.START_PORT, type=CommandType.INTEGER, required=true, description="the start port for the rule")
private Integer startPort;
@@ -58,6 +57,7 @@ public class CreateIpForwardingRuleCmd extends BaseAsyncCreateCmd implements Por
@Parameter(name=ApiConstants.PROTOCOL, type=CommandType.STRING, required=true, description="the protocol for the rule. Valid values are TCP or UDP.")
private String protocol;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
@@ -66,10 +66,6 @@ public class CreateIpForwardingRuleCmd extends BaseAsyncCreateCmd implements Por
public String getIpAddress() {
return ipAddress;
}
-
- public long getVirtualMachineId() {
- return virtualMachineId;
- }
public int getStartPort() {
return startPort;
@@ -113,7 +109,7 @@ public class CreateIpForwardingRuleCmd extends BaseAsyncCreateCmd implements Por
public void create() {
PortForwardingRule rule;
try {
- rule = _rulesService.createPortForwardingRule(this, virtualMachineId, true);
+ rule = _rulesService.createPortForwardingRule(this, getVirtualMachineId(), true);
} catch (NetworkRuleConflictException e) {
s_logger.info("Unable to create Port Forwarding Rule due to " + e.getMessage());
throw new ServerApiException(BaseCmd.NETWORK_RULE_CONFLICT_ERROR, e.getMessage());
@@ -140,7 +136,7 @@ public class CreateIpForwardingRuleCmd extends BaseAsyncCreateCmd implements Por
@Override
public String getEventDescription() {
- return ("Creating an ipforwarding 1:1 NAT rule for "+ipAddress+" with virtual machine:"+virtualMachineId);
+ return ("Creating an ipforwarding 1:1 NAT rule for "+ipAddress+" with virtual machine:"+ getVirtualMachineId());
}
@Override
@@ -225,5 +221,16 @@ public class CreateIpForwardingRuleCmd extends BaseAsyncCreateCmd implements Por
public boolean isOneToOneNat() {
return true;
}
+
+ @Override
+ public long getVirtualMachineId() {
+ IpAddress ip = _networkService.getIp(new Ip(ipAddress));
+ if (ip == null) {
+ throw new InvalidParameterValueException("Ip address " + ipAddress + " doesn't exist in the system");
+ } else {
+ return _networkService.getIp(new Ip(ipAddress)).getVmId();
+ }
+
+ }
}
diff --git a/api/src/com/cloud/api/commands/DeleteIpForwardingRuleCmd.java b/api/src/com/cloud/api/commands/DeleteIpForwardingRuleCmd.java
index e1d49946b5e..1049a9d7001 100644
--- a/api/src/com/cloud/api/commands/DeleteIpForwardingRuleCmd.java
+++ b/api/src/com/cloud/api/commands/DeleteIpForwardingRuleCmd.java
@@ -28,6 +28,7 @@ import com.cloud.api.Parameter;
import com.cloud.api.ServerApiException;
import com.cloud.api.response.SuccessResponse;
import com.cloud.event.EventTypes;
+import com.cloud.exception.InvalidParameterValueException;
import com.cloud.network.rules.PortForwardingRule;
@Implementation(description="Deletes an ip forwarding rule", responseObject=SuccessResponse.class)
@@ -79,7 +80,12 @@ public class DeleteIpForwardingRuleCmd extends BaseAsyncCmd {
@Override
public long getEntityOwnerId() {
if (ownerId == null) {
- ownerId = _entityMgr.findById(PortForwardingRule.class, id).getAccountId();
+ PortForwardingRule rule = _entityMgr.findById(PortForwardingRule.class, id);
+ if (rule == null) {
+ throw new InvalidParameterValueException("Unable to find firewall rule by id: " + id);
+ } else {
+ ownerId = rule.getAccountId();
+ }
}
return ownerId;
}
diff --git a/api/src/com/cloud/api/commands/DisableOneToOneNat.java b/api/src/com/cloud/api/commands/DisableOneToOneNat.java
new file mode 100644
index 00000000000..724cc69b8bd
--- /dev/null
+++ b/api/src/com/cloud/api/commands/DisableOneToOneNat.java
@@ -0,0 +1,88 @@
+/**
+ * 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.api.commands;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.api.ApiConstants;
+import com.cloud.api.BaseAsyncCmd;
+import com.cloud.api.BaseCmd;
+import com.cloud.api.Implementation;
+import com.cloud.api.Parameter;
+import com.cloud.api.ServerApiException;
+import com.cloud.api.response.SuccessResponse;
+import com.cloud.event.EventTypes;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.network.IpAddress;
+import com.cloud.utils.net.Ip;
+
+@Implementation(description="Disables one to one nat rule", responseObject=SuccessResponse.class)
+public class DisableOneToOneNat extends BaseAsyncCmd {
+ public static final Logger s_logger = Logger.getLogger(DeletePortForwardingRuleCmd.class.getName());
+ private static final String s_name = "disableonetoonenatresponse";
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @Parameter(name=ApiConstants.IP_ADDRESS, type=CommandType.STRING, required=true, description="the public IP address for which one-to-one nat feature is being disableed")
+ private String ipAddress;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public String getIpAddress() {
+ return ipAddress;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+ @Override
+ public String getCommandName() {
+ return s_name;
+ }
+
+ @Override
+ public String getEventType() {
+ return EventTypes.EVENT_DISABLE_ONE_TO_ONE_NAT;
+ }
+
+ @Override
+ public String getEventDescription() {
+ return ("Disabling one to one nat for ip=" + ipAddress);
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return _entityMgr.findById(IpAddress.class, ipAddress).getAccountId();
+ }
+
+ @Override
+ public void execute() throws ResourceUnavailableException {
+ boolean result = _rulesService.disableOneToOneNat(new Ip(ipAddress));
+
+ if (result) {
+ SuccessResponse response = new SuccessResponse(getCommandName());
+ this.setResponseObject(response);
+ } else {
+ throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Failed to disable oneToOne nat rule");
+ }
+ }
+}
diff --git a/api/src/com/cloud/api/commands/EnableOneToOneNat.java b/api/src/com/cloud/api/commands/EnableOneToOneNat.java
new file mode 100644
index 00000000000..9f92391294f
--- /dev/null
+++ b/api/src/com/cloud/api/commands/EnableOneToOneNat.java
@@ -0,0 +1,86 @@
+/**
+ * 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.api.commands;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.api.ApiConstants;
+import com.cloud.api.BaseCmd;
+import com.cloud.api.Implementation;
+import com.cloud.api.Parameter;
+import com.cloud.api.ServerApiException;
+import com.cloud.api.response.SuccessResponse;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.utils.net.Ip;
+
+@Implementation(description="Enables one to one nat for the ip address", responseObject=SuccessResponse.class)
+public class EnableOneToOneNat extends BaseCmd{
+ public static final Logger s_logger = Logger.getLogger(CreateIpForwardingRuleCmd.class.getName());
+
+ private static final String s_name = "enableonetoonenatresponse";
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @Parameter(name=ApiConstants.IP_ADDRESS, type=CommandType.STRING, required=true, description="the public IP address for which one-to-one nat feature is being enabled")
+ private String ipAddress;
+
+ @Parameter(name=ApiConstants.VIRTUAL_MACHINE_ID, type=CommandType.LONG, required=true, description="the ID of the virtual machine for enabling one-to-one nat feature")
+ private Long virtualMachineId;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public String getIpAddress() {
+ return ipAddress;
+ }
+
+ public Long getVirtualMachineId() {
+ return virtualMachineId;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public String getCommandName() {
+ return s_name;
+ }
+
+ @Override
+ public void execute(){
+ try {
+ boolean result = _rulesService.enableOneToOneNat(new Ip(ipAddress), virtualMachineId);
+ if (result) {
+ SuccessResponse response = new SuccessResponse(getCommandName());
+ this.setResponseObject(response);
+ } else {
+ throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Failed to enable one-to-one nat");
+ }
+ } catch (NetworkRuleConflictException ex) {
+ s_logger.info("Network rule conflict: " + ex.getMessage());
+ s_logger.trace("Network Rule Conflict: ", ex);
+ throw new ServerApiException(BaseCmd.NETWORK_RULE_CONFLICT_ERROR, ex.getMessage());
+ }
+ }
+
+}
diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java
index 22c038bf787..28b4614e405 100755
--- a/api/src/com/cloud/event/EventTypes.java
+++ b/api/src/com/cloud/event/EventTypes.java
@@ -183,4 +183,9 @@ public class EventTypes {
//Custom certificates
public static final String EVENT_UPLOAD_CUSTOM_CERTIFICATE = "UPLOAD.CUSTOM.CERTIFICATE";
+
+ //OneToOnenat
+ public static final String EVENT_ENABLE_ONE_TO_ONE_NAT = "ONETOONENAT.ENABLE";
+ public static final String EVENT_DISABLE_ONE_TO_ONE_NAT = "ONETOONENAT.DISABLE";
+
}
diff --git a/api/src/com/cloud/network/IpAddress.java b/api/src/com/cloud/network/IpAddress.java
index e4552298684..1eaeabada82 100644
--- a/api/src/com/cloud/network/IpAddress.java
+++ b/api/src/com/cloud/network/IpAddress.java
@@ -66,4 +66,6 @@ public interface IpAddress extends ControlledEntity {
boolean readyToUse();
Long getAssociatedWithNetworkId();
+
+ Long getVmId();
}
diff --git a/api/src/com/cloud/network/NetworkService.java b/api/src/com/cloud/network/NetworkService.java
index a6a83d83f85..affd873cfae 100644
--- a/api/src/com/cloud/network/NetworkService.java
+++ b/api/src/com/cloud/network/NetworkService.java
@@ -32,6 +32,7 @@ import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.offering.NetworkOffering;
+import com.cloud.utils.net.Ip;
public interface NetworkService {
@@ -58,4 +59,6 @@ public interface NetworkService {
Network getNetwork(long networkId);
+ IpAddress getIp(Ip ip);
+
}
diff --git a/api/src/com/cloud/network/rules/RulesService.java b/api/src/com/cloud/network/rules/RulesService.java
index cb985a1ac08..f8f39f6aff7 100644
--- a/api/src/com/cloud/network/rules/RulesService.java
+++ b/api/src/com/cloud/network/rules/RulesService.java
@@ -54,4 +54,9 @@ public interface RulesService {
public List extends PortForwardingRule> listPortForwardingRules(ListPortForwardingRulesCmd cmd);
boolean applyPortForwardingRules(Ip ip, Account caller) throws ResourceUnavailableException;
+
+ boolean enableOneToOneNat(Ip ipAddress, long vmId) throws NetworkRuleConflictException;
+
+ boolean disableOneToOneNat(Ip ipAddress);
+
}
diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in
index f0c9608dd6e..2577e8e26fb 100755
--- a/client/tomcatconf/commands.properties.in
+++ b/client/tomcatconf/commands.properties.in
@@ -111,9 +111,11 @@ deletePortForwardingRule=com.cloud.api.commands.DeletePortForwardingRuleCmd;15
#### updatePortForwardingRule=com.cloud.api.commands.UpdatePortForwardingRuleCmd;15
#### NAT commands
+enableOneToOneNat=com.cloud.api.commands.EnableOneToOneNat;15
createIpForwardingRule=com.cloud.api.commands.CreateIpForwardingRuleCmd;15
deleteIpForwardingRule=com.cloud.api.commands.DeleteIpForwardingRuleCmd;15
listIpForwardingRules=com.cloud.api.commands.ListIpForwardingRulesCmd;15
+disableOneToOneNat=com.cloud.api.commands.DisableOneToOneNat;15
#### load balancer commands
createLoadBalancerRule=com.cloud.api.commands.CreateLoadBalancerRuleCmd;15
diff --git a/server/src/com/cloud/network/IPAddressVO.java b/server/src/com/cloud/network/IPAddressVO.java
index eb170e81f9c..ebee43c37e5 100644
--- a/server/src/com/cloud/network/IPAddressVO.java
+++ b/server/src/com/cloud/network/IPAddressVO.java
@@ -65,6 +65,9 @@ public class IPAddressVO implements IpAddress {
@Column(name="one_to_one_nat")
private boolean oneToOneNat;
+ @Column(name="vm_id")
+ private Long associatedWithVmId;
+
@Column(name="state")
private State state;
@@ -121,6 +124,15 @@ public class IPAddressVO implements IpAddress {
public void setAssociatedWithNetworkId(Long networkId) {
this.associatedWithNetworkId = networkId;
}
+
+ @Override
+ public Long getVmId() {
+ return associatedWithVmId;
+ }
+
+ public void setAssociatedWithVmId(Long vmId) {
+ this.associatedWithVmId = vmId;
+ }
@Override
public Long getAllocatedInDomainId() {
@@ -193,5 +205,6 @@ public class IPAddressVO implements IpAddress {
@Override
public String toString() {
return new StringBuilder("Ip[").append(address).append("-").append(dataCenterId).append("]").toString();
- }
+ }
+
}
diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java
index abf7c114066..e28bb9e89a0 100755
--- a/server/src/com/cloud/network/NetworkManagerImpl.java
+++ b/server/src/com/cloud/network/NetworkManagerImpl.java
@@ -1979,4 +1979,9 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag
assert vos.size() <= 1 : "If we have multiple networks of the same type, then this method should no longer be used.";
return vos.size() == 1 ? vos.get(0) : null;
}
+
+ @Override
+ public IpAddress getIp(Ip ip) {
+ return _ipAddressDao.findById(ip);
+ }
}
diff --git a/server/src/com/cloud/network/addr/PublicIp.java b/server/src/com/cloud/network/addr/PublicIp.java
index 277c3e97faf..26477bbdc61 100644
--- a/server/src/com/cloud/network/addr/PublicIp.java
+++ b/server/src/com/cloud/network/addr/PublicIp.java
@@ -79,6 +79,11 @@ public class PublicIp implements PublicIpAddress {
return _addr.isOneToOneNat();
}
+ @Override
+ public Long getVmId() {
+ return _addr.getVmId();
+ }
+
@Override
public Date getAllocatedTime() {
return _addr.getAllocatedTime();
diff --git a/server/src/com/cloud/network/dao/FirewallRulesDao.java b/server/src/com/cloud/network/dao/FirewallRulesDao.java
index b5a99cbb4ce..abe9fddb486 100644
--- a/server/src/com/cloud/network/dao/FirewallRulesDao.java
+++ b/server/src/com/cloud/network/dao/FirewallRulesDao.java
@@ -29,7 +29,7 @@ import com.cloud.utils.net.Ip;
* Data Access Object for user_ip_address and ip_forwarding tables
*/
public interface FirewallRulesDao extends GenericDao {
- List listByIpAndNotRevoked(Ip ip);
+ List listByIpAndNotRevoked(Ip ip, Boolean isOneToOneNat);
boolean setStateToAdd(FirewallRuleVO rule);
diff --git a/server/src/com/cloud/network/dao/FirewallRulesDaoImpl.java b/server/src/com/cloud/network/dao/FirewallRulesDaoImpl.java
index c1d2afcd907..a63556e042f 100644
--- a/server/src/com/cloud/network/dao/FirewallRulesDaoImpl.java
+++ b/server/src/com/cloud/network/dao/FirewallRulesDaoImpl.java
@@ -59,6 +59,7 @@ public class FirewallRulesDaoImpl extends GenericDaoBase i
IpNotRevokedSearch = createSearchBuilder();
IpNotRevokedSearch.and("ip", IpNotRevokedSearch.entity().getSourceIpAddress(), Op.EQ);
IpNotRevokedSearch.and("state", IpNotRevokedSearch.entity().getState(), Op.NEQ);
+ IpNotRevokedSearch.and("oneToOneNat", IpNotRevokedSearch.entity().isOneToOneNat(), Op.EQ);
IpNotRevokedSearch.done();
ReleaseSearch = createSearchBuilder();
@@ -91,10 +92,13 @@ public class FirewallRulesDaoImpl extends GenericDaoBase i
}
@Override
- public List listByIpAndNotRevoked(Ip ip) {
+ public List listByIpAndNotRevoked(Ip ip, Boolean isOneToOneNat) {
SearchCriteria sc = IpNotRevokedSearch.create();
sc.setParameters("ip", ip);
sc.setParameters("state", State.Revoke);
+ if (isOneToOneNat != null) {
+ sc.setParameters("oneToOneNat", isOneToOneNat);
+ }
return listBy(sc);
}
diff --git a/server/src/com/cloud/network/dao/IPAddressDaoImpl.java b/server/src/com/cloud/network/dao/IPAddressDaoImpl.java
index 9ac8ff3bdb2..67ec35bf2d2 100644
--- a/server/src/com/cloud/network/dao/IPAddressDaoImpl.java
+++ b/server/src/com/cloud/network/dao/IPAddressDaoImpl.java
@@ -152,6 +152,7 @@ public class IPAddressDaoImpl extends GenericDaoBase implements
address.setAllocatedTime(null);
address.setSourceNat(false);
address.setOneToOneNat(false);
+ address.setAssociatedWithVmId(null);
address.setState(State.Free);
address.setAssociatedWithNetworkId(null);
update(ipAddress, address);
diff --git a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java
index 6ec8a81ffe5..8681197df7a 100644
--- a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java
+++ b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java
@@ -36,7 +36,6 @@ import com.cloud.api.commands.UpdateLoadBalancerRuleCmd;
import com.cloud.dc.dao.VlanDao;
import com.cloud.domain.dao.DomainDao;
import com.cloud.event.EventTypes;
-import com.cloud.event.EventVO;
import com.cloud.event.UsageEventVO;
import com.cloud.event.dao.EventDao;
import com.cloud.event.dao.UsageEventDao;
@@ -399,7 +398,7 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesManager,
@Override
public boolean removeAllLoadBalanacers(Ip ip) {
- List rules = _rulesDao.listByIpAndNotRevoked(ip);
+ List rules = _rulesDao.listByIpAndNotRevoked(ip, null);
if (rules != null)
s_logger.debug("Found " + rules.size() + " lb rules to cleanup");
for (FirewallRule rule : rules) {
diff --git a/server/src/com/cloud/network/rules/RulesManagerImpl.java b/server/src/com/cloud/network/rules/RulesManagerImpl.java
index 768f789ac48..0d4b80591f0 100644
--- a/server/src/com/cloud/network/rules/RulesManagerImpl.java
+++ b/server/src/com/cloud/network/rules/RulesManagerImpl.java
@@ -83,7 +83,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager {
public void detectRulesConflict(FirewallRule newRule, IpAddress ipAddress) throws NetworkRuleConflictException {
assert newRule.getSourceIpAddress().equals(ipAddress.getAddress()) : "You passed in an ip address that doesn't match the address in the new rule";
- List rules = _firewallDao.listByIpAndNotRevoked(newRule.getSourceIpAddress());
+ List rules = _firewallDao.listByIpAndNotRevoked(newRule.getSourceIpAddress(), null);
assert (rules.size() >= 1) : "For network rules, we now always first persist the rule and then check for network conflicts so we should at least have one rule at this point.";
for (FirewallRuleVO rule : rules) {
@@ -92,9 +92,9 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager {
}
if (rule.isOneToOneNat() && !newRule.isOneToOneNat()) {
- throw new NetworkRuleConflictException("There is already port forwarding rule specified for the " + newRule.getSourceIpAddress());
+ throw new NetworkRuleConflictException("There is 1 to 1 Nat rule specified for the " + newRule.getSourceIpAddress());
} else if (!rule.isOneToOneNat() && newRule.isOneToOneNat()) {
- throw new NetworkRuleConflictException("There is already 1 to 1 Nat rule specified for the " + newRule.getSourceIpAddress());
+ throw new NetworkRuleConflictException("There is already firewall rule specified for the " + newRule.getSourceIpAddress());
}
if (rule.getNetworkId() != newRule.getNetworkId() && rule.getState() != State.Revoke) {
@@ -133,6 +133,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager {
throw new InvalidParameterValueException("Invalid user vm: " + userVm.getId());
}
+ _accountMgr.checkAccess(caller, ipAddress);
_accountMgr.checkAccess(caller, userVm);
// validate that IP address and userVM belong to the same account
@@ -193,13 +194,10 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager {
long accountId = network.getAccountId();
long domainId = network.getDomainId();
- checkIpAndUserVm(ipAddress, vm, caller);
- if (isNat && (ipAddress.isSourceNat())) {
+ if (isNat && (ipAddress.isSourceNat() || !ipAddress.isOneToOneNat() || ipAddress.getVmId() == null)) {
throw new NetworkRuleConflictException("Can't do one to one NAT on ip address: " + ipAddress.getAddress());
}
- Transaction txn = Transaction.currentTxn();
- txn.start();
PortForwardingRuleVO newRule =
new PortForwardingRuleVO(rule.getXid(),
rule.getSourceIpAddress(),
@@ -213,12 +211,6 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager {
accountId,
domainId, vmId, isNat);
newRule = _forwardingDao.persist(newRule);
-
- if (isNat && !ipAddress.isOneToOneNat()) {
- ipAddress.setOneToOneNat(true);
- _ipAddressDao.update(ipAddress.getAddress(), ipAddress);
- }
- txn.commit();
try {
detectRulesConflict(newRule, ipAddress);
@@ -230,21 +222,48 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager {
_usageEventDao.persist(usageEvent);
return newRule;
} catch (Exception e) {
- txn.start();
_forwardingDao.remove(newRule.getId());
- if (isNat) {
- ipAddress.setOneToOneNat(false);
- _ipAddressDao.update(ipAddress.getAddress(), ipAddress);
- }
- txn.commit();
if (e instanceof NetworkRuleConflictException) {
throw (NetworkRuleConflictException)e;
}
-
throw new CloudRuntimeException("Unable to add rule for " + newRule.getSourceIpAddress(), e);
}
}
+ @Override
+ public boolean enableOneToOneNat(Ip ip, long vmId) throws NetworkRuleConflictException{
+ IPAddressVO ipAddress = _ipAddressDao.findById(ip);
+ Account caller = UserContext.current().getCaller();
+
+ UserVmVO vm = null;
+ vm = _vmDao.findById(vmId);
+ if (vm == null) {
+ throw new InvalidParameterValueException("Can't enable one-to-one nat for the address " + ipAddress + ", invalid virtual machine id specified (" + vmId + ").");
+ }
+
+ checkIpAndUserVm(ipAddress, vm, caller);
+
+ if (ipAddress.isSourceNat()) {
+ throw new InvalidParameterValueException("Can't enable one to one nat, ip address: " + ip.addr() + " is a sourceNat ip address");
+ }
+
+ if (!ipAddress.isOneToOneNat()) {
+ List rules = _firewallDao.listByIpAndNotRevoked(ip, false);
+ if (rules != null && !rules.isEmpty()) {
+ throw new NetworkRuleConflictException("Failed to enable one to one nat for the ip address " + ipAddress.getAddress() + " as it already has firewall rules assigned");
+ }
+ } else {
+ if (ipAddress.getVmId() != null && ipAddress.getVmId().longValue() != vmId) {
+ throw new NetworkRuleConflictException("Failed to enable one to one nat for the ip address " + ipAddress.getAddress() + " and vm id=" + vmId + " as it's already assigned to antoher vm");
+ }
+ }
+
+ ipAddress.setOneToOneNat(true);
+ ipAddress.setAssociatedWithVmId(vmId);
+ return _ipAddressDao.update(ipAddress.getAddress(), ipAddress);
+
+ }
+
protected Pair getUserVmGuestIpAddress(UserVm vm) {
Ip dstIp = null;
List extends Nic> nics = _networkMgr.getNics(vm);
@@ -276,14 +295,6 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager {
rule.setState(State.Revoke);
_firewallDao.update(rule.getId(), rule);
}
- if (rule.isOneToOneNat()) {
- if (s_logger.isDebugEnabled()) {
- s_logger.debug("Removing one to one nat so setting the ip back to one to one nat is false: " + rule.getSourceIpAddress());
- }
- IPAddressVO ipAddress = _ipAddressDao.findById(rule.getSourceIpAddress());
- ipAddress.setOneToOneNat(false);
- _ipAddressDao.update(ipAddress.getAddress(), ipAddress);
- }
// Save and create the event
String ruleName = rule.getPurpose() == Purpose.Firewall ? "Firewall" : (rule.isOneToOneNat() ? "ip forwarding" : "port forwarding");
@@ -339,7 +350,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager {
}
public List extends FirewallRule> listFirewallRules(Ip ip) {
- return _firewallDao.listByIpAndNotRevoked(ip);
+ return _firewallDao.listByIpAndNotRevoked(ip, null);
}
@Override
@@ -557,5 +568,53 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager {
public List extends PortForwardingRule> listByNetworkId(long networkId) {
return _forwardingDao.listByNetworkId(networkId);
}
+
+ public boolean isLastOneToOneNatRule(FirewallRule ruleToCheck) {
+ List rules = _firewallDao.listByIpAndNotRevoked(ruleToCheck.getSourceIpAddress(), false);
+ if (rules != null && !rules.isEmpty()) {
+ for (FirewallRuleVO rule : rules) {
+ if (ruleToCheck.getId() == rule.getId()) {
+ continue;
+ }
+ if (rule.isOneToOneNat()) {
+ return false;
+ }
+ }
+ } else {
+ return true;
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean disableOneToOneNat(Ip ip){
+ Account caller = UserContext.current().getCaller();
+
+ IPAddressVO ipAddress = _ipAddressDao.findById(ip);
+ checkIpAndUserVm(ipAddress, null, caller);
+
+ if (!ipAddress.isOneToOneNat()) {
+ throw new InvalidParameterValueException("One to one nat is not enabled for the ip: " + ip.addr());
+ }
+
+ List rules = _firewallDao.listByIpAndNotRevoked(ip, true);
+ if (rules != null) {
+ for (FirewallRuleVO rule : rules) {
+ rule.setState(State.Revoke);
+ _firewallDao.update(rule.getId(), rule);
+ }
+ }
+
+ if (applyPortForwardingRules(ip, true)) {
+ ipAddress.setOneToOneNat(false);
+ ipAddress.setAssociatedWithVmId(null);
+ _ipAddressDao.update(ipAddress.getAddress(), ipAddress);
+ return true;
+ } else {
+ s_logger.warn("Failed to disable one to one nat for the ip address " + ip.addr());
+ return false;
+ }
+ }
}
diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql
index 75a788995ef..777564f2c03 100755
--- a/setup/db/create-schema.sql
+++ b/setup/db/create-schema.sql
@@ -682,6 +682,7 @@ CREATE TABLE `cloud`.`user_ip_address` (
`allocated` datetime NULL COMMENT 'Date this ip was allocated to someone',
`vlan_db_id` bigint unsigned NOT NULL,
`one_to_one_nat` int(1) unsigned NOT NULL default '0',
+ `vm_id` bigint unsigned COMMENT 'vm id the one_to_one nat ip is assigned to',
`state` char(32) NOT NULL default 'Free' COMMENT 'state of the ip address',
`mac_address` bigint unsigned NOT NULL COMMENT 'mac address of this ip',
`network_id` bigint unsigned COMMENT 'network this public ip address is associated with',