From 26b75fc05d092a12d2629780afc708c4cf61225f Mon Sep 17 00:00:00 2001 From: abhishek Date: Wed, 10 Nov 2010 11:03:04 -0800 Subject: [PATCH] this is a good point to check the code in; have completed a part of the enhancement's code; with create and delete ip forwarding rule commands and the skeleton for port to rule map with associated table --- client/tomcatconf/commands.properties.in | 3 + .../cloud/network/IprulePortrangeMapVO.java | 88 ++++++ .../cloud/network/dao/FirewallRulesDao.java | 3 +- .../network/dao/FirewallRulesDaoImpl.java | 18 +- .../network/dao/IprulePortrangeMapDao.java | 30 +++ .../dao/IprulePortrangeMapDaoImpl.java | 57 ++++ .../commands/CreateIpForwardingRuleCmd.java | 93 +++++++ .../commands/CreatePortForwardingRuleCmd.java | 4 +- .../commands/DeleteIpForwardingRuleCmd.java | 85 ++++++ .../commands/DeletePortForwardingRuleCmd.java | 6 +- .../commands/UpdatePortForwardingRuleCmd.java | 4 +- .../src/com/cloud/network/NetworkManager.java | 7 +- .../com/cloud/network/NetworkManagerImpl.java | 254 ++++++++++++------ setup/db/create-schema.sql | 9 + 14 files changed, 569 insertions(+), 92 deletions(-) create mode 100644 core/src/com/cloud/network/IprulePortrangeMapVO.java create mode 100644 core/src/com/cloud/network/dao/IprulePortrangeMapDao.java create mode 100644 core/src/com/cloud/network/dao/IprulePortrangeMapDaoImpl.java create mode 100644 server/src/com/cloud/api/commands/CreateIpForwardingRuleCmd.java create mode 100644 server/src/com/cloud/api/commands/DeleteIpForwardingRuleCmd.java diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index c347dc11073..8a106fffc42 100755 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -107,6 +107,9 @@ createPortForwardingRule=com.cloud.api.commands.CreatePortForwardingRuleCmd;15 deletePortForwardingRule=com.cloud.api.commands.DeletePortForwardingRuleCmd;15 updatePortForwardingRule=com.cloud.api.commands.UpdatePortForwardingRuleCmd;15 +#### NAT commands +createIpForwardingRule=com.cloud.api.commands.CreateIpForwardingRuleCmd;15 + #### load balancer commands createLoadBalancerRule=com.cloud.api.commands.CreateLoadBalancerRuleCmd;15 deleteLoadBalancerRule=com.cloud.api.commands.DeleteLoadBalancerRuleCmd;15 diff --git a/core/src/com/cloud/network/IprulePortrangeMapVO.java b/core/src/com/cloud/network/IprulePortrangeMapVO.java new file mode 100644 index 00000000000..2304a7d854a --- /dev/null +++ b/core/src/com/cloud/network/IprulePortrangeMapVO.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.network; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name=("iprule_portrange_map")) +public class IprulePortrangeMapVO { + @Id + @GeneratedValue(strategy=GenerationType.IDENTITY) + @Column(name="id") + private Long id; + + @Column(name="fwrule_id") + private Long fwruleId; + + @Column(name="start_port") + private String startPort = null; + + @Column(name="end_port") + private String endPort = null; + + public IprulePortrangeMapVO() { + } + + public IprulePortrangeMapVO(Long id, Long ruleId, String startPort, String endPort) { + this.id = id; + this.fwruleId = ruleId; + this.startPort = startPort; + this.endPort = endPort; + + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getFwruleId() { + return fwruleId; + } + + public void setFwruleId(Long fwruleId) { + this.fwruleId = fwruleId; + } + + public String getStartPort() { + return startPort; + } + + public void setStartPort(String startPort) { + this.startPort = startPort; + } + + public String getEndPort() { + return endPort; + } + + public void setEndPort(String endPort) { + this.endPort = endPort; + } +} + diff --git a/core/src/com/cloud/network/dao/FirewallRulesDao.java b/core/src/com/cloud/network/dao/FirewallRulesDao.java index 7db42df3bf6..ef2bd4f0ed4 100644 --- a/core/src/com/cloud/network/dao/FirewallRulesDao.java +++ b/core/src/com/cloud/network/dao/FirewallRulesDao.java @@ -44,5 +44,6 @@ public interface FirewallRulesDao extends GenericDao { public List listBySecurityGroupId(long securityGroupId); public List listByLoadBalancerId(long loadBalancerId); public List listForwardingByPubAndPrivIp(boolean forwarding, String publicIPAddress, String privateIp); - public FirewallRuleVO findByGroupAndPrivateIp(long groupId, String privateIp, boolean forwarding); + public FirewallRuleVO findByGroupAndPrivateIp(long groupId, String privateIp, boolean forwarding); + List findByPublicIpPrivateIpForNatRule(String publicIp,String privateIp); } diff --git a/core/src/com/cloud/network/dao/FirewallRulesDaoImpl.java b/core/src/com/cloud/network/dao/FirewallRulesDaoImpl.java index 55bce08b553..be3dee36020 100644 --- a/core/src/com/cloud/network/dao/FirewallRulesDaoImpl.java +++ b/core/src/com/cloud/network/dao/FirewallRulesDaoImpl.java @@ -55,7 +55,8 @@ public class FirewallRulesDaoImpl extends GenericDaoBase i protected SearchBuilder FWByPrivateIPSearch; protected SearchBuilder RulesExcludingPubIpPort; protected SearchBuilder FWByGroupId; - protected SearchBuilder FWByGroupAndPrivateIp; + protected SearchBuilder FWByGroupAndPrivateIp; + protected SearchBuilder FWByPrivateIpPrivatePortPublicIpPublicPortSearch; protected FirewallRulesDaoImpl() { } @@ -124,6 +125,13 @@ public class FirewallRulesDaoImpl extends GenericDaoBase i FWByGroupAndPrivateIp.and("forwarding", FWByGroupAndPrivateIp.entity().isForwarding(), SearchCriteria.Op.EQ); FWByGroupAndPrivateIp.done(); + FWByPrivateIpPrivatePortPublicIpPublicPortSearch = createSearchBuilder(); + FWByPrivateIpPrivatePortPublicIpPublicPortSearch.and("publicIpAddress", FWByPrivateIpPrivatePortPublicIpPublicPortSearch.entity().getPublicIpAddress(), SearchCriteria.Op.EQ); + FWByPrivateIpPrivatePortPublicIpPublicPortSearch.and("privateIpAddress", FWByPrivateIpPrivatePortPublicIpPublicPortSearch.entity().getPrivateIpAddress(), SearchCriteria.Op.EQ); + FWByPrivateIpPrivatePortPublicIpPublicPortSearch.and("privatePort", FWByPrivateIpPrivatePortPublicIpPublicPortSearch.entity().getPrivatePort(), SearchCriteria.Op.NULL); + FWByPrivateIpPrivatePortPublicIpPublicPortSearch.and("publicPort", FWByPrivateIpPrivatePortPublicIpPublicPortSearch.entity().getPublicPort(), SearchCriteria.Op.NULL); + FWByPrivateIpPrivatePortPublicIpPublicPortSearch.done(); + return true; } @@ -306,5 +314,13 @@ public class FirewallRulesDaoImpl extends GenericDaoBase i sc.setParameters("forwarding", forwarding); return findOneBy(sc); + } + + @Override + public List findByPublicIpPrivateIpForNatRule(String publicIp, String privateIp){ + SearchCriteria sc = FWByPrivateIpPrivatePortPublicIpPublicPortSearch.create(); + sc.setParameters("publicIpAddress", publicIp); + sc.setParameters("privateIpAddress", privateIp); + return listBy(sc); } } diff --git a/core/src/com/cloud/network/dao/IprulePortrangeMapDao.java b/core/src/com/cloud/network/dao/IprulePortrangeMapDao.java new file mode 100644 index 00000000000..00da1107718 --- /dev/null +++ b/core/src/com/cloud/network/dao/IprulePortrangeMapDao.java @@ -0,0 +1,30 @@ +/** + * 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.dao; + +import java.util.List; + +import com.cloud.network.IprulePortrangeMapVO; +import com.cloud.utils.db.GenericDao; + +public interface IprulePortrangeMapDao extends GenericDao { + + List listPortRecordsForRule(Long ruleId); + +} diff --git a/core/src/com/cloud/network/dao/IprulePortrangeMapDaoImpl.java b/core/src/com/cloud/network/dao/IprulePortrangeMapDaoImpl.java new file mode 100644 index 00000000000..bbd5e1eec86 --- /dev/null +++ b/core/src/com/cloud/network/dao/IprulePortrangeMapDaoImpl.java @@ -0,0 +1,57 @@ +/** + * 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.dao; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.util.ArrayList; +import java.util.List; + +import javax.ejb.Local; + +import org.apache.log4j.Logger; + +import com.cloud.network.FirewallRuleVO; +import com.cloud.network.IprulePortrangeMapVO; +import com.cloud.network.LoadBalancerVO; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; + +@Local(value={IprulePortrangeMapDao.class}) +public class IprulePortrangeMapDaoImpl extends GenericDaoBase implements IprulePortrangeMapDao { + private static final Logger s_logger = Logger.getLogger(IprulePortrangeMapDaoImpl.class); + + private final SearchBuilder ListByForwardingRule; + + protected IprulePortrangeMapDaoImpl() { + ListByForwardingRule = createSearchBuilder(); + ListByForwardingRule.and("ruleId", ListByForwardingRule.entity().getFwruleId(), SearchCriteria.Op.EQ); + ListByForwardingRule.done(); + + } + + @Override + public List listPortRecordsForRule(Long ruleId) { + SearchCriteria sc = ListByForwardingRule.create(); + sc.setParameters("ruleId", ruleId); + return listBy(sc); + } +} diff --git a/server/src/com/cloud/api/commands/CreateIpForwardingRuleCmd.java b/server/src/com/cloud/api/commands/CreateIpForwardingRuleCmd.java new file mode 100644 index 00000000000..51439062aab --- /dev/null +++ b/server/src/com/cloud/api/commands/CreateIpForwardingRuleCmd.java @@ -0,0 +1,93 @@ +/** + * 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.ApiResponseHelper; +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.FirewallRuleResponse; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.network.FirewallRuleVO; + +@Implementation(description="Creates an ip forwarding rule") +public class CreateIpForwardingRuleCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(CreateIpForwardingRuleCmd.class.getName()); + + private static final String s_name = "createipforwardingruleresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @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; + + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public String getIpAddress() { + return ipAddress; + } + + public Long getVirtualMachineId() { + return virtualMachineId; + } + + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getName() { + return s_name; + } + + @Override + public void execute() throws ServerApiException, InvalidParameterValueException, PermissionDeniedException, InsufficientAddressCapacityException, InsufficientCapacityException, ConcurrentOperationException{ + try { + FirewallRuleVO result = _networkMgr.createIpForwardingRule(this); + if (result != null) { + FirewallRuleResponse fwResponse = ApiResponseHelper.createFirewallRuleResponse(result); + fwResponse.setResponseName(getName()); + this.setResponseObject(fwResponse); + } else { + //throw new ServerApiException(NET_CREATE_IPFW_RULE_ERROR, "An existing rule for ipAddress / port / protocol of " + ipAddress + " / " + publicPort + " / " + protocol + " exits."); + } + } catch (NetworkRuleConflictException ex) { + throw new ServerApiException(BaseCmd.INTERNAL_ERROR, ex.getMessage()); + } + } + +} diff --git a/server/src/com/cloud/api/commands/CreatePortForwardingRuleCmd.java b/server/src/com/cloud/api/commands/CreatePortForwardingRuleCmd.java index 67c3dd603b5..cd988eef39d 100644 --- a/server/src/com/cloud/api/commands/CreatePortForwardingRuleCmd.java +++ b/server/src/com/cloud/api/commands/CreatePortForwardingRuleCmd.java @@ -36,8 +36,8 @@ import com.cloud.exception.PermissionDeniedException; import com.cloud.network.FirewallRuleVO; @Implementation(description="Creates a port forwarding rule") -public class CreateIPForwardingRuleCmd extends BaseCmd { - public static final Logger s_logger = Logger.getLogger(CreateIPForwardingRuleCmd.class.getName()); +public class CreatePortForwardingRuleCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(CreatePortForwardingRuleCmd.class.getName()); private static final String s_name = "createportforwardingruleresponse"; diff --git a/server/src/com/cloud/api/commands/DeleteIpForwardingRuleCmd.java b/server/src/com/cloud/api/commands/DeleteIpForwardingRuleCmd.java new file mode 100644 index 00000000000..8f77eb1b57b --- /dev/null +++ b/server/src/com/cloud/api/commands/DeleteIpForwardingRuleCmd.java @@ -0,0 +1,85 @@ +/** + * 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.ApiResponseHelper; +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.FirewallRuleResponse; +import com.cloud.api.response.SuccessResponse; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.network.FirewallRuleVO; + +@Implementation(description="Deletes an ip forwarding rule") +public class DeleteIpForwardingRuleCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(DeleteIpForwardingRuleCmd.class.getName()); + + private static final String s_name = "deleteipforwardingruleresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.LONG, required=true, description="the id of the forwarding rule") + private Long id; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getName() { + return s_name; + } + + @Override + public void execute() throws ServerApiException, InvalidParameterValueException, PermissionDeniedException, InsufficientAddressCapacityException, InsufficientCapacityException, ConcurrentOperationException{ + try { + boolean result = false; + result = _networkMgr.deleteIpForwardingRule(this); + if (result) { + SuccessResponse response = new SuccessResponse(getName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Failed to delete ip forwarding rule"); + } + } catch (Exception ex) { + throw new ServerApiException(BaseCmd.INTERNAL_ERROR, ex.getMessage()); + } + } + +} diff --git a/server/src/com/cloud/api/commands/DeletePortForwardingRuleCmd.java b/server/src/com/cloud/api/commands/DeletePortForwardingRuleCmd.java index ddfb872db95..e93cb77eb31 100644 --- a/server/src/com/cloud/api/commands/DeletePortForwardingRuleCmd.java +++ b/server/src/com/cloud/api/commands/DeletePortForwardingRuleCmd.java @@ -32,8 +32,8 @@ import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.PermissionDeniedException; @Implementation(description="Deletes a port forwarding rule") -public class DeleteIPForwardingRuleCmd extends BaseCmd { - public static final Logger s_logger = Logger.getLogger(DeleteIPForwardingRuleCmd.class.getName()); +public class DeletePortForwardingRuleCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(DeletePortForwardingRuleCmd.class.getName()); private static final String s_name = "deleteportforwardingruleresponse"; ///////////////////////////////////////////////////// @@ -63,7 +63,7 @@ public class DeleteIPForwardingRuleCmd extends BaseCmd { @Override public void execute() throws ServerApiException, InvalidParameterValueException, PermissionDeniedException, InsufficientAddressCapacityException, InsufficientCapacityException, ConcurrentOperationException{ - boolean result = _networkMgr.deleteIpForwardingRule(this); + boolean result = _networkMgr.deletePortForwardingRule(this); if (result) { SuccessResponse response = new SuccessResponse(getName()); this.setResponseObject(response); diff --git a/server/src/com/cloud/api/commands/UpdatePortForwardingRuleCmd.java b/server/src/com/cloud/api/commands/UpdatePortForwardingRuleCmd.java index 35dea1922fe..3674c320107 100644 --- a/server/src/com/cloud/api/commands/UpdatePortForwardingRuleCmd.java +++ b/server/src/com/cloud/api/commands/UpdatePortForwardingRuleCmd.java @@ -21,8 +21,8 @@ import com.cloud.network.IPAddressVO; import com.cloud.user.Account; @Implementation(description="Updates a port forwarding rule. Only the private port and the virtual machine can be updated.") -public class UpdateIPForwardingRuleCmd extends BaseAsyncCmd { - public static final Logger s_logger = Logger.getLogger(UpdateIPForwardingRuleCmd.class.getName()); +public class UpdatePortForwardingRuleCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(UpdatePortForwardingRuleCmd.class.getName()); private static final String s_name = "updateportforwardingruleresponse"; ///////////////////////////////////////////////////// diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index dce23943464..b01de8ba1dc 100644 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -27,6 +27,7 @@ import com.cloud.api.commands.CreateIpForwardingRuleCmd; import com.cloud.api.commands.CreatePortForwardingRuleCmd; import com.cloud.api.commands.CreateLoadBalancerRuleCmd; import com.cloud.api.commands.CreateRemoteAccessVpnCmd; +import com.cloud.api.commands.DeleteIpForwardingRuleCmd; import com.cloud.api.commands.DeletePortForwardingRuleCmd; import com.cloud.api.commands.DeleteLoadBalancerRuleCmd; import com.cloud.api.commands.DeleteRemoteAccessVpnCmd; @@ -304,8 +305,6 @@ public interface NetworkManager { List listPublicIpAddressesInVirtualNetwork(long accountId, long dcId, Boolean sourceNat); public boolean disassociateIpAddress(DisassociateIPAddrCmd cmd); - - public boolean deleteIpForwardingRule(DeletePortForwardingRuleCmd cmd); List setupNetworkConfiguration(Account owner, NetworkOfferingVO offering, DeploymentPlan plan); List setupNetworkConfiguration(Account owner, NetworkOfferingVO offering, NetworkConfiguration predefined, DeploymentPlan plan); @@ -364,4 +363,8 @@ public interface NetworkManager { String getNextAvailableMacAddressInNetwork(long networkConfigurationId); FirewallRuleVO createIpForwardingRule(CreateIpForwardingRuleCmd cmd) throws InvalidParameterValueException, PermissionDeniedException, NetworkRuleConflictException; + + public boolean deletePortForwardingRule(DeletePortForwardingRuleCmd cmd); + + public boolean deleteIpForwardingRule(DeleteIpForwardingRuleCmd cmd); } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index d6517012391..03cd2310d4b 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -53,6 +53,7 @@ import com.cloud.api.commands.CreateIpForwardingRuleCmd; import com.cloud.api.commands.CreatePortForwardingRuleCmd; import com.cloud.api.commands.CreateLoadBalancerRuleCmd; import com.cloud.api.commands.CreateRemoteAccessVpnCmd; +import com.cloud.api.commands.DeleteIpForwardingRuleCmd; import com.cloud.api.commands.DeletePortForwardingRuleCmd; import com.cloud.api.commands.DeleteLoadBalancerRuleCmd; import com.cloud.api.commands.DeleteRemoteAccessVpnCmd; @@ -107,6 +108,7 @@ import com.cloud.network.Network.TrafficType; import com.cloud.network.configuration.NetworkGuru; import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.IprulePortrangeMapDao; import com.cloud.network.dao.LoadBalancerDao; import com.cloud.network.dao.LoadBalancerVMMapDao; import com.cloud.network.dao.NetworkConfigurationDao; @@ -218,6 +220,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag @Inject RemoteAccessVpnDao _remoteAccessVpnDao = null; @Inject VpnUserDao _vpnUsersDao = null; @Inject DomainRouterManager _routerMgr; + @Inject IprulePortrangeMapDao _iprulePortrangeMapDao = null; @Inject(adapter=NetworkGuru.class) Adapters _networkGurus; @@ -2510,7 +2513,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } @Override @DB - public boolean deleteIpForwardingRule(DeletePortForwardingRuleCmd cmd) { + public boolean deletePortForwardingRule(DeletePortForwardingRuleCmd cmd) { Long ruleId = cmd.getId(); Long userId = UserContext.current().getUserId(); Account account = UserContext.current().getAccount(); @@ -2937,96 +2940,185 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag return _networkConfigDao.findById(id); } - @Override + @Override @DB public FirewallRuleVO createIpForwardingRule(CreateIpForwardingRuleCmd cmd) throws InvalidParameterValueException, PermissionDeniedException, NetworkRuleConflictException { - // validate IP Address exists - IPAddressVO ipAddress = _ipAddressDao.findById(cmd.getIpAddress()); - if (ipAddress == null) { - throw new InvalidParameterValueException("Unable to create ip forwarding rule on address " + ipAddress + ", invalid IP address specified."); - } + + Transaction txn = Transaction.currentTxn(); + txn.start(); + UserVmVO userVM = null; + FirewallRuleVO newFwRule = null; + boolean locked = false; + try { + // validate IP Address exists + IPAddressVO ipAddress = _ipAddressDao.findById(cmd.getIpAddress()); + if (ipAddress == null) { + throw new InvalidParameterValueException("Unable to create ip forwarding rule on address " + ipAddress + ", invalid IP address specified."); + } - // validate user VM exists - UserVmVO userVM = _vmDao.findById(cmd.getVirtualMachineId()); - if (userVM == null) { - throw new InvalidParameterValueException("Unable to create ip forwarding rule on address " + ipAddress + ", invalid virtual machine id specified (" + cmd.getVirtualMachineId() + ")."); - } + // validate user VM exists + userVM = _vmDao.findById(cmd.getVirtualMachineId()); + if (userVM == null) { + throw new InvalidParameterValueException("Unable to create ip forwarding rule on address " + ipAddress + ", invalid virtual machine id specified (" + cmd.getVirtualMachineId() + ")."); + } + + //sync point; cannot lock on rule ; hence sync on vm + userVM = _vmDao.acquireInLockTable(userVM.getId()); + + if(userVM == null){ + s_logger.warn("Unable to acquire lock on user vm for creating 1-1 NAT rule"); + return newFwRule; + }else{ + locked = true; + } - // validate that IP address and userVM belong to the same account - if ((ipAddress.getAccountId() == null) || (ipAddress.getAccountId().longValue() != userVM.getAccountId())) { - throw new InvalidParameterValueException("Unable to create ip forwarding rule, IP address " + ipAddress + " owner is not the same as owner of virtual machine " + userVM.toString()); - } + // validate that IP address and userVM belong to the same account + if ((ipAddress.getAccountId() == null) || (ipAddress.getAccountId().longValue() != userVM.getAccountId())) { + throw new InvalidParameterValueException("Unable to create ip forwarding rule, IP address " + ipAddress + " owner is not the same as owner of virtual machine " + userVM.toString()); + } - // validate that userVM is in the same availability zone as the IP address - if (ipAddress.getDataCenterId() != userVM.getDataCenterId()) { - throw new InvalidParameterValueException("Unable to create ip forwarding rule, IP address " + ipAddress + " is not in the same availability zone as virtual machine " + userVM.toString()); - } + // validate that userVM is in the same availability zone as the IP address + if (ipAddress.getDataCenterId() != userVM.getDataCenterId()) { + throw new InvalidParameterValueException("Unable to create ip forwarding rule, IP address " + ipAddress + " is not in the same availability zone as virtual machine " + userVM.toString()); + } - // if an admin account was passed in, or no account was passed in, make sure we honor the accountName/domainId parameters - Account account = UserContext.current().getAccount(); - if (account != null) { - if ((account.getType() == Account.ACCOUNT_TYPE_ADMIN) || (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN)) { - if (!_domainDao.isChildDomain(account.getDomainId(), userVM.getDomainId())) { - throw new PermissionDeniedException("Unable to create ip forwarding rule, IP address " + ipAddress + " to virtual machine " + cmd.getVirtualMachineId() + ", permission denied."); - } - } else if (account.getId() != userVM.getAccountId()) { - throw new PermissionDeniedException("Unable to create ip forwarding rule, IP address " + ipAddress + " to virtual machine " + cmd.getVirtualMachineId() + ", permission denied."); - } - } + // if an admin account was passed in, or no account was passed in, make sure we honor the accountName/domainId parameters + Account account = UserContext.current().getAccount(); + if (account != null) { + if ((account.getType() == Account.ACCOUNT_TYPE_ADMIN) || (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN)) { + if (!_domainDao.isChildDomain(account.getDomainId(), userVM.getDomainId())) { + throw new PermissionDeniedException("Unable to create ip forwarding rule, IP address " + ipAddress + " to virtual machine " + cmd.getVirtualMachineId() + ", permission denied."); + } + } else if (account.getId() != userVM.getAccountId()) { + throw new PermissionDeniedException("Unable to create ip forwarding rule, IP address " + ipAddress + " to virtual machine " + cmd.getVirtualMachineId() + ", permission denied."); + } + } - // check for ip address/port conflicts by checking existing forwarding and load balancing rules - List existingRulesOnPubIp = _rulesDao.listIPForwarding(ipAddress.getAddress()); + // check for ip address/port conflicts by checking existing forwarding and load balancing rules + List existingNatRules = _rulesDao.findByPublicIpPrivateIpForNatRule(cmd.getIpAddress(), userVM.getGuestIpAddress()); + + if(existingNatRules.size() > 0){ + throw new NetworkRuleConflictException("The specified rule for public ip:"+cmd.getIpAddress()+" vm id:"+cmd.getVirtualMachineId()+" already exists"); + } + + newFwRule = new FirewallRuleVO(); + newFwRule.setEnabled(true); + newFwRule.setForwarding(true); + newFwRule.setPrivatePort(null); + newFwRule.setProtocol("NAT");//protocol cannot be null; adding this as a NAT + newFwRule.setPublicPort(null); + newFwRule.setPublicIpAddress(ipAddress.getAddress()); + newFwRule.setPrivateIpAddress(userVM.getGuestIpAddress()); + newFwRule.setGroupId(null); + _rulesDao.persist(newFwRule); - // FIXME: The mapped ports should be String, String, List since more than one proto can be mapped... - Map>> mappedPublicPorts = new HashMap>>(); + // Save and create the event + String description; + String ruleName = "ip forwarding"; + String level = EventVO.LEVEL_INFO; - if (existingRulesOnPubIp != null) { - for (FirewallRuleVO fwRule : existingRulesOnPubIp) { - Ternary> portMappings = mappedPublicPorts.get(fwRule.getPublicPort()); - List protocolList = null; - if (portMappings == null) { - protocolList = new ArrayList(); - } else { - protocolList = portMappings.third(); - } - protocolList.add(fwRule.getProtocol()); - mappedPublicPorts.put(fwRule.getPublicPort(), new Ternary>(fwRule.getPrivateIpAddress(), fwRule.getPrivatePort(), protocolList)); - } - } + description = "created new " + ruleName + " rule [" + newFwRule.getPublicIpAddress() + ":" + newFwRule.getPublicPort() + "]->[" + + newFwRule.getPrivateIpAddress() + ":" + newFwRule.getPrivatePort() + "]" + " " + newFwRule.getProtocol(); - FirewallRuleVO newFwRule = new FirewallRuleVO(); - newFwRule.setEnabled(true); - newFwRule.setForwarding(true); -// newFwRule.setPrivatePort(privatePort); -// newFwRule.setProtocol(protocol); -// newFwRule.setPublicPort(publicPort); - newFwRule.setPublicIpAddress(ipAddress.getAddress()); - newFwRule.setPrivateIpAddress(userVM.getGuestIpAddress()); -// newFwRule.setGroupId(securityGroupId); - newFwRule.setGroupId(null); - - // In 1.0 the rules were always persisted when a user created a rule. When the rules get sent down - // the stopOnError parameter is set to false, so the agent will apply all rules that it can. That - // behavior is preserved here by persisting the rule before sending it to the agent. - _rulesDao.persist(newFwRule); - - boolean success = updateFirewallRule(newFwRule, null, null); - - // Save and create the event - String description; - String ruleName = "ip forwarding"; - String level = EventVO.LEVEL_INFO; - - if (success == true) { - description = "created new " + ruleName + " rule [" + newFwRule.getPublicIpAddress() + ":" + newFwRule.getPublicPort() + "]->[" - + newFwRule.getPrivateIpAddress() + ":" + newFwRule.getPrivatePort() + "]" + " " + newFwRule.getProtocol(); - } else { - level = EventVO.LEVEL_ERROR; - description = "failed to create new " + ruleName + " rule [" + newFwRule.getPublicIpAddress() + ":" + newFwRule.getPublicPort() + "]->[" - + newFwRule.getPrivateIpAddress() + ":" + newFwRule.getPrivatePort() + "]" + " " + newFwRule.getProtocol(); - } - - EventUtils.saveEvent(UserContext.current().getUserId(), userVM.getAccountId(), level, EventTypes.EVENT_NET_RULE_ADD, description); + EventUtils.saveEvent(UserContext.current().getUserId(), userVM.getAccountId(), level, EventTypes.EVENT_NET_RULE_ADD, description); + + txn.commit(); + } catch (Exception e) { + s_logger.warn("Unable to create new firewall rule for 1:1 NAT"); + txn.rollback(); + }finally{ + if(locked) + _vmDao.releaseFromLockTable(userVM.getId()); + } return newFwRule; } + + @Override @DB + public boolean deleteIpForwardingRule(DeleteIpForwardingRuleCmd cmd) { + Long ruleId = cmd.getId(); + Long userId = UserContext.current().getUserId(); + Account account = UserContext.current().getAccount(); + + //verify input parameters here + FirewallRuleVO rule = _firewallRulesDao.findById(ruleId); + if (rule == null) { + throw new InvalidParameterValueException("Unable to find port forwarding rule " + ruleId); + } + + String publicIp = rule.getPublicIpAddress(); + + + IPAddressVO ipAddress = _ipAddressDao.findById(publicIp); + if (ipAddress == null) { + throw new InvalidParameterValueException("Unable to find IP address for ip forwarding rule " + ruleId); + } + + // although we are not writing these values to the DB, we will check + // them out of an abundance + // of caution (may not be warranted) + + Account ruleOwner = _accountDao.findById(ipAddress.getAccountId()); + if (ruleOwner == null) { + throw new InvalidParameterValueException("Unable to find owning account for ip forwarding rule " + ruleId); + } + + // if an admin account was passed in, or no account was passed in, make sure we honor the accountName/domainId parameters + if (account != null) { + if (isAdmin(account.getType())) { + if (!_domainDao.isChildDomain(account.getDomainId(), ruleOwner.getDomainId())) { + throw new PermissionDeniedException("Unable to delete ip forwarding rule " + ruleId + ", permission denied."); + } + } else if (account.getId() != ruleOwner.getId()) { + throw new PermissionDeniedException("Unable to delete ip forwarding rule " + ruleId + ", permission denied."); + } + } + + Transaction txn = Transaction.currentTxn(); + boolean locked = false; + boolean success = false; + try { + + rule = _firewallRulesDao.acquireInLockTable(ruleId); + if (rule == null) { + throw new PermissionDeniedException("Unable to obtain lock on record for deletion"); + } + + locked = true; + txn.start(); + //if there is an open port range associated with the rule, don't allow deletion + List portRecordsForRule = _iprulePortrangeMapDao.listPortRecordsForRule(ruleId); + + if (portRecordsForRule != null && portRecordsForRule.size() > 0) { + throw new InvalidParameterValueException("Cannot delete rule as port mappings for this rule exist; please delete those mappings first"); + } + + success = _firewallRulesDao.remove(ruleId); + + String description; + String type = EventTypes.EVENT_NET_RULE_DELETE; + String level = EventVO.LEVEL_INFO; + String ruleName = rule.isForwarding() ? "ip forwarding" : "load balancer"; + + if (success) { + description = "deleted " + ruleName + " rule [" + publicIp + ":" + rule.getPublicPort() + "]->[" + rule.getPrivateIpAddress() + ":" + + rule.getPrivatePort() + "] " + rule.getProtocol(); + } else { + level = EventVO.LEVEL_ERROR; + description = "Error while deleting " + ruleName + " rule [" + publicIp + ":" + rule.getPublicPort() + "]->[" + rule.getPrivateIpAddress() + ":" + + rule.getPrivatePort() + "] " + rule.getProtocol(); + } + EventUtils.saveEvent(userId, ipAddress.getAccountId(), level, type, description); + txn.commit(); + }catch (Exception ex) { + txn.rollback(); + s_logger.error("Unexpected exception deleting port forwarding rule " + ruleId, ex); + return false; + }finally { + if (locked) { + _ipAddressDao.releaseFromLockTable(publicIp); + } + txn.close(); + } + return success; + } } diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index 91c0e1276e0..b73d95cf875 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -445,6 +445,15 @@ CREATE TABLE `cloud`.`ip_forwarding` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; +CREATE TABLE `cloud`.`iprule_portrange_map`( + `id` bigint unsigned NOT NULL auto_increment, + `fwrule_id` bigint unsigned NOT NULL, + `start_port` varchar(10) default NULL, + `end_port` varchar(10) default NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; + + CREATE TABLE `cloud`.`host` ( `id` bigint unsigned NOT NULL auto_increment, `name` varchar(255) NOT NULL,