bug 6338: refactored a bunch of code, and enhanced the logic to expunge the port fwding rules, anytime we expunge the vm

status 6338: resolved fixed
This commit is contained in:
abhishek 2010-09-29 17:51:00 -07:00
parent c9dc6de7a3
commit c7257505e3
6 changed files with 289 additions and 227 deletions

View File

@ -44,5 +44,6 @@ public interface FirewallRulesDao extends GenericDao<FirewallRuleVO, Long> {
public List<FirewallRuleVO> listBySecurityGroupId(long securityGroupId);
public List<FirewallRuleVO> listByLoadBalancerId(long loadBalancerId);
public List<FirewallRuleVO> 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);
public List<FirewallRuleVO> listByPrivateIp(String privateIp);
}

View File

@ -306,5 +306,12 @@ public class FirewallRulesDaoImpl extends GenericDaoBase<FirewallRuleVO, Long> i
sc.setParameters("forwarding", forwarding);
return findOneActiveBy(sc);
}
}
@Override
public List<FirewallRuleVO> listByPrivateIp(String privateIp) {
SearchCriteria sc = FWByPrivateIPSearch.create();
sc.setParameters("privateIpAddress", privateIp);
return listActiveBy(sc);
}
}

View File

@ -27,7 +27,9 @@ import com.cloud.dc.HostPodVO;
import com.cloud.dc.VlanVO;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InternalErrorException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.host.HostVO;
import com.cloud.network.FirewallRuleVO;
@ -211,4 +213,5 @@ public interface NetworkManager extends Manager {
*/
List<IPAddressVO> listPublicIpAddressesInVirtualNetwork(long accountId, long dcId, Boolean sourceNat);
public void deleteRule(long ruleId, long userId, long accountId) throws InvalidParameterValueException, PermissionDeniedException, InternalErrorException;
}

View File

@ -184,6 +184,8 @@ public class NetworkManagerImpl implements NetworkManager, VirtualMachineManager
AsyncJobManager _asyncMgr;
StoragePoolDao _storagePoolDao = null;
ServiceOfferingDao _serviceOfferingDao = null;
FirewallRulesDao _firewallRulesDao;
IPAddressDao _publicIpAddressDao;
long _routerTemplateId = -1;
int _routerRamSize;
@ -1731,6 +1733,16 @@ public class NetworkManagerImpl implements NetworkManager, VirtualMachineManager
throw new ConfigurationException("Unable to get the configuration dao.");
}
_firewallRulesDao = locator.getDao(FirewallRulesDao.class);
if (_firewallRulesDao == null) {
throw new ConfigurationException("Unable to get the firewall rules dao.");
}
_publicIpAddressDao = locator.getDao(IPAddressDao.class);
if (_publicIpAddressDao == null) {
throw new ConfigurationException("Unable to get the ip address dao.");
}
_configMgr = locator.getManager(ConfigurationManager.class);
if (_configMgr == null) {
throw new ConfigurationException("Unable to get the configuration manager.");
@ -2417,4 +2429,243 @@ public class NetworkManagerImpl implements NetworkManager, VirtualMachineManager
return _ipAddressDao.search(ipAddressSC, null);
}
@Override
public void deleteRule(long ruleId, long userId, long accountId)throws InvalidParameterValueException, PermissionDeniedException,InternalErrorException
{
Exception e = null;
try {
FirewallRuleVO rule = _firewallRulesDao.findById(ruleId);
if (rule != null) {
boolean success = false;
try {
if (rule.isForwarding()) {
success = deleteIpForwardingRule(userId, accountId, rule.getPublicIpAddress(), rule.getPublicPort(), rule.getPrivateIpAddress(), rule.getPrivatePort(),
rule.getProtocol());
} else {
success = deleteLoadBalancingRule(userId, accountId, rule.getPublicIpAddress(), rule.getPublicPort(), rule.getPrivateIpAddress(), rule.getPrivatePort(),
rule.getAlgorithm());
}
} catch (Exception ex) {
e = ex;
}
String description;
String type = EventTypes.EVENT_NET_RULE_DELETE;
String level = EventVO.LEVEL_INFO;
String ruleName = rule.isForwarding() ? "ip forwarding" : "load balancer";
if (success) {
String desc = "deleted " + ruleName + " rule [" + rule.getPublicIpAddress() + ":" + rule.getPublicPort() + "]->[" + rule.getPrivateIpAddress() + ":"
+ rule.getPrivatePort() + "] " + rule.getProtocol();
if (!rule.isForwarding()) {
desc = desc + ", algorithm = " + rule.getAlgorithm();
}
description = desc;
} else {
level = EventVO.LEVEL_ERROR;
String desc = "deleted " + ruleName + " rule [" + rule.getPublicIpAddress() + ":" + rule.getPublicPort() + "]->[" + rule.getPrivateIpAddress() + ":"
+ rule.getPrivatePort() + "] " + rule.getProtocol();
if (!rule.isForwarding()) {
desc = desc + ", algorithm = " + rule.getAlgorithm();
}
description = desc;
}
saveEvent(userId, accountId, level, type, description);
}
} finally {
if (e != null) {
if (e instanceof InvalidParameterValueException) {
throw (InvalidParameterValueException) e;
} else if (e instanceof PermissionDeniedException) {
throw (PermissionDeniedException) e;
} else if (e instanceof InternalErrorException) {
throw (InternalErrorException) e;
}
}
}
}
@DB
protected boolean deleteIpForwardingRule(long userId, long accountId, String publicIp, String publicPort, String privateIp, String privatePort, String proto)
throws PermissionDeniedException, InvalidParameterValueException, InternalErrorException {
Transaction txn = Transaction.currentTxn();
boolean locked = false;
try {
AccountVO accountVO = _accountDao.findById(accountId);
if (accountVO == null) {
// throw this exception because hackers can use the api to probe
// for existing user ids
throw new PermissionDeniedException("Account does not own supplied address");
}
// although we are not writing these values to the DB, we will check
// them out of an abundance
// of caution (may not be warranted)
if (!NetUtils.isValidPort(publicPort) || !NetUtils.isValidPort(privatePort)) {
throw new InvalidParameterValueException("Invalid value for port");
}
// if (!NetUtils.isValidPrivateIp(privateIp, _configs.get("guest.ip.network"))) {
// throw new InvalidParameterValueException("Invalid private ip address");
// }
if (!NetUtils.isValidProto(proto)) {
throw new InvalidParameterValueException("Invalid protocol");
}
IPAddressVO ipVO = _publicIpAddressDao.acquire(publicIp);
if (ipVO == null) {
// throw this exception because hackers can use the api to probe for allocated ips
throw new PermissionDeniedException("User does not own supplied address");
}
locked = true;
if ((ipVO.getAllocated() == null) || (ipVO.getAccountId() == null) || (ipVO.getAccountId().longValue() != accountId)) {
// FIXME: if admin account, make sure the user is visible in the
// admin's domain, or has that checking been done by this point?
if (!BaseCmd.isAdmin(accountVO.getType())) {
throw new PermissionDeniedException("User/account does not own supplied address");
}
}
txn.start();
List<FirewallRuleVO> fwdings = _firewallRulesDao.listIPForwardingForUpdate(publicIp, publicPort, proto);
FirewallRuleVO fwRule = null;
if (fwdings.size() == 0) {
throw new InvalidParameterValueException("No such rule");
} else if (fwdings.size() == 1) {
fwRule = fwdings.get(0);
if (fwRule.getPrivateIpAddress().equalsIgnoreCase(privateIp) && fwRule.getPrivatePort().equals(privatePort)) {
_firewallRulesDao.delete(fwRule.getId());
} else {
throw new InvalidParameterValueException("No such rule");
}
} else {
throw new InternalErrorException("Multiple matches. Please contact support");
}
fwRule.setEnabled(false);
boolean success = updateFirewallRule(fwRule, null, null);
if (!success) {
throw new InternalErrorException("Failed to update router");
}
txn.commit();
return success;
} catch (Throwable e) {
if (e instanceof InvalidParameterValueException) {
throw (InvalidParameterValueException) e;
} else if (e instanceof PermissionDeniedException) {
throw (PermissionDeniedException) e;
} else if (e instanceof InternalErrorException) {
s_logger.warn("ManagementServer error", e);
throw (InternalErrorException) e;
}
s_logger.warn("ManagementServer error", e);
} finally {
if (locked) {
_publicIpAddressDao.release(publicIp);
}
}
return false;
}
@DB
private boolean deleteLoadBalancingRule(long userId, long accountId, String publicIp, String publicPort, String privateIp, String privatePort, String algo)
throws PermissionDeniedException, InvalidParameterValueException, InternalErrorException {
Transaction txn = Transaction.currentTxn();
boolean locked = false;
try {
AccountVO accountVO = _accountDao.findById(accountId);
if (accountVO == null) {
// throw this exception because hackers can use the api to probe
// for existing user ids
throw new PermissionDeniedException("Account does not own supplied address");
}
// although we are not writing these values to the DB, we will check
// them out of an abundance
// of caution (may not be warranted)
if (!NetUtils.isValidPort(publicPort) || !NetUtils.isValidPort(privatePort)) {
throw new InvalidParameterValueException("Invalid value for port");
}
// if (!NetUtils.isValidPrivateIp(privateIp, _configs.get("guest.ip.network"))) {
// throw new InvalidParameterValueException("Invalid private ip address");
// }
if (!NetUtils.isValidAlgorithm(algo)) {
throw new InvalidParameterValueException("Invalid protocol");
}
IPAddressVO ipVO = _publicIpAddressDao.acquire(publicIp);
if (ipVO == null) {
// throw this exception because hackers can use the api to probe
// for allocated ips
throw new PermissionDeniedException("User does not own supplied address");
}
locked = true;
if ((ipVO.getAllocated() == null) || (ipVO.getAccountId() == null) || (ipVO.getAccountId().longValue() != accountId)) {
// FIXME: the user visible from the admin account's domain? has
// that check been done already?
if (!BaseCmd.isAdmin(accountVO.getType())) {
throw new PermissionDeniedException("User does not own supplied address");
}
}
List<FirewallRuleVO> fwdings = _firewallRulesDao.listLoadBalanceRulesForUpdate(publicIp, publicPort, algo);
FirewallRuleVO fwRule = null;
if (fwdings.size() == 0) {
throw new InvalidParameterValueException("No such rule");
}
for (FirewallRuleVO frv : fwdings) {
if (frv.getPrivateIpAddress().equalsIgnoreCase(privateIp) && frv.getPrivatePort().equals(privatePort)) {
fwRule = frv;
break;
}
}
if (fwRule == null) {
throw new InvalidParameterValueException("No such rule");
}
txn.start();
fwRule.setEnabled(false);
_firewallRulesDao.update(fwRule.getId(), fwRule);
boolean success = updateFirewallRule(fwRule, null, null);
if (!success) {
throw new InternalErrorException("Failed to update router");
}
_firewallRulesDao.delete(fwRule.getId());
txn.commit();
return success;
} catch (Throwable e) {
if (e instanceof InvalidParameterValueException) {
throw (InvalidParameterValueException) e;
} else if (e instanceof PermissionDeniedException) {
throw (PermissionDeniedException) e;
} else if (e instanceof InternalErrorException) {
s_logger.warn("ManagementServer error", e);
throw (InternalErrorException) e;
}
s_logger.warn("ManagementServer error", e);
} finally {
if (locked) {
_publicIpAddressDao.release(publicIp);
}
}
return false;
}
private Long saveEvent(Long userId, Long accountId, String level, String type, String description) {
EventVO event = new EventVO();
event.setUserId(userId);
event.setAccountId(accountId);
event.setType(type);
event.setDescription(description);
event.setLevel(level);
event = _eventDao.persist(event);
return event.getId();
}
}

View File

@ -3643,175 +3643,6 @@ public class ManagementServerImpl implements ManagementServer {
return _asyncMgr.submitAsyncJob(job);
}
@DB
protected boolean deleteIpForwardingRule(long userId, long accountId, String publicIp, String publicPort, String privateIp, String privatePort, String proto)
throws PermissionDeniedException, InvalidParameterValueException, InternalErrorException {
Transaction txn = Transaction.currentTxn();
boolean locked = false;
try {
AccountVO accountVO = _accountDao.findById(accountId);
if (accountVO == null) {
// throw this exception because hackers can use the api to probe
// for existing user ids
throw new PermissionDeniedException("Account does not own supplied address");
}
// although we are not writing these values to the DB, we will check
// them out of an abundance
// of caution (may not be warranted)
if (!NetUtils.isValidPort(publicPort) || !NetUtils.isValidPort(privatePort)) {
throw new InvalidParameterValueException("Invalid value for port");
}
// if (!NetUtils.isValidPrivateIp(privateIp, _configs.get("guest.ip.network"))) {
// throw new InvalidParameterValueException("Invalid private ip address");
// }
if (!NetUtils.isValidProto(proto)) {
throw new InvalidParameterValueException("Invalid protocol");
}
IPAddressVO ipVO = _publicIpAddressDao.acquire(publicIp);
if (ipVO == null) {
// throw this exception because hackers can use the api to probe for allocated ips
throw new PermissionDeniedException("User does not own supplied address");
}
locked = true;
if ((ipVO.getAllocated() == null) || (ipVO.getAccountId() == null) || (ipVO.getAccountId().longValue() != accountId)) {
// FIXME: if admin account, make sure the user is visible in the
// admin's domain, or has that checking been done by this point?
if (!BaseCmd.isAdmin(accountVO.getType())) {
throw new PermissionDeniedException("User/account does not own supplied address");
}
}
txn.start();
List<FirewallRuleVO> fwdings = _firewallRulesDao.listIPForwardingForUpdate(publicIp, publicPort, proto);
FirewallRuleVO fwRule = null;
if (fwdings.size() == 0) {
throw new InvalidParameterValueException("No such rule");
} else if (fwdings.size() == 1) {
fwRule = fwdings.get(0);
if (fwRule.getPrivateIpAddress().equalsIgnoreCase(privateIp) && fwRule.getPrivatePort().equals(privatePort)) {
_firewallRulesDao.delete(fwRule.getId());
} else {
throw new InvalidParameterValueException("No such rule");
}
} else {
throw new InternalErrorException("Multiple matches. Please contact support");
}
fwRule.setEnabled(false);
boolean success = _networkMgr.updateFirewallRule(fwRule, null, null);
if (!success) {
throw new InternalErrorException("Failed to update router");
}
txn.commit();
return success;
} catch (Throwable e) {
if (e instanceof InvalidParameterValueException) {
throw (InvalidParameterValueException) e;
} else if (e instanceof PermissionDeniedException) {
throw (PermissionDeniedException) e;
} else if (e instanceof InternalErrorException) {
s_logger.warn("ManagementServer error", e);
throw (InternalErrorException) e;
}
s_logger.warn("ManagementServer error", e);
} finally {
if (locked) {
_publicIpAddressDao.release(publicIp);
}
}
return false;
}
@DB
private boolean deleteLoadBalancingRule(long userId, long accountId, String publicIp, String publicPort, String privateIp, String privatePort, String algo)
throws PermissionDeniedException, InvalidParameterValueException, InternalErrorException {
Transaction txn = Transaction.currentTxn();
boolean locked = false;
try {
AccountVO accountVO = _accountDao.findById(accountId);
if (accountVO == null) {
// throw this exception because hackers can use the api to probe
// for existing user ids
throw new PermissionDeniedException("Account does not own supplied address");
}
// although we are not writing these values to the DB, we will check
// them out of an abundance
// of caution (may not be warranted)
if (!NetUtils.isValidPort(publicPort) || !NetUtils.isValidPort(privatePort)) {
throw new InvalidParameterValueException("Invalid value for port");
}
// if (!NetUtils.isValidPrivateIp(privateIp, _configs.get("guest.ip.network"))) {
// throw new InvalidParameterValueException("Invalid private ip address");
// }
if (!NetUtils.isValidAlgorithm(algo)) {
throw new InvalidParameterValueException("Invalid protocol");
}
IPAddressVO ipVO = _publicIpAddressDao.acquire(publicIp);
if (ipVO == null) {
// throw this exception because hackers can use the api to probe
// for allocated ips
throw new PermissionDeniedException("User does not own supplied address");
}
locked = true;
if ((ipVO.getAllocated() == null) || (ipVO.getAccountId() == null) || (ipVO.getAccountId().longValue() != accountId)) {
// FIXME: the user visible from the admin account's domain? has
// that check been done already?
if (!BaseCmd.isAdmin(accountVO.getType())) {
throw new PermissionDeniedException("User does not own supplied address");
}
}
List<FirewallRuleVO> fwdings = _firewallRulesDao.listLoadBalanceRulesForUpdate(publicIp, publicPort, algo);
FirewallRuleVO fwRule = null;
if (fwdings.size() == 0) {
throw new InvalidParameterValueException("No such rule");
}
for (FirewallRuleVO frv : fwdings) {
if (frv.getPrivateIpAddress().equalsIgnoreCase(privateIp) && frv.getPrivatePort().equals(privatePort)) {
fwRule = frv;
break;
}
}
if (fwRule == null) {
throw new InvalidParameterValueException("No such rule");
}
txn.start();
fwRule.setEnabled(false);
_firewallRulesDao.update(fwRule.getId(), fwRule);
boolean success = _networkMgr.updateFirewallRule(fwRule, null, null);
if (!success) {
throw new InternalErrorException("Failed to update router");
}
_firewallRulesDao.delete(fwRule.getId());
txn.commit();
return success;
} catch (Throwable e) {
if (e instanceof InvalidParameterValueException) {
throw (InvalidParameterValueException) e;
} else if (e instanceof PermissionDeniedException) {
throw (PermissionDeniedException) e;
} else if (e instanceof InternalErrorException) {
s_logger.warn("ManagementServer error", e);
throw (InternalErrorException) e;
}
s_logger.warn("ManagementServer error", e);
} finally {
if (locked) {
_publicIpAddressDao.release(publicIp);
}
}
return false;
}
@Override
public List<EventVO> getEvents(long userId, long accountId, Long domainId, String type, String level, Date startDate, Date endDate) {
@ -6025,60 +5856,9 @@ public class ManagementServerImpl implements ManagementServer {
return _asyncMgr.submitAsyncJob(job);
}
public void deleteRule(long ruleId, long userId, long accountId) throws InvalidParameterValueException, PermissionDeniedException, InternalErrorException {
Exception e = null;
try {
FirewallRuleVO rule = _firewallRulesDao.findById(ruleId);
if (rule != null) {
boolean success = false;
try {
if (rule.isForwarding()) {
success = deleteIpForwardingRule(userId, accountId, rule.getPublicIpAddress(), rule.getPublicPort(), rule.getPrivateIpAddress(), rule.getPrivatePort(),
rule.getProtocol());
} else {
success = deleteLoadBalancingRule(userId, accountId, rule.getPublicIpAddress(), rule.getPublicPort(), rule.getPrivateIpAddress(), rule.getPrivatePort(),
rule.getAlgorithm());
}
} catch (Exception ex) {
e = ex;
}
String description;
String type = EventTypes.EVENT_NET_RULE_DELETE;
String level = EventVO.LEVEL_INFO;
String ruleName = rule.isForwarding() ? "ip forwarding" : "load balancer";
if (success) {
String desc = "deleted " + ruleName + " rule [" + rule.getPublicIpAddress() + ":" + rule.getPublicPort() + "]->[" + rule.getPrivateIpAddress() + ":"
+ rule.getPrivatePort() + "] " + rule.getProtocol();
if (!rule.isForwarding()) {
desc = desc + ", algorithm = " + rule.getAlgorithm();
}
description = desc;
} else {
level = EventVO.LEVEL_ERROR;
String desc = "deleted " + ruleName + " rule [" + rule.getPublicIpAddress() + ":" + rule.getPublicPort() + "]->[" + rule.getPrivateIpAddress() + ":"
+ rule.getPrivatePort() + "] " + rule.getProtocol();
if (!rule.isForwarding()) {
desc = desc + ", algorithm = " + rule.getAlgorithm();
}
description = desc;
}
saveEvent(userId, accountId, level, type, description);
}
} finally {
if (e != null) {
if (e instanceof InvalidParameterValueException) {
throw (InvalidParameterValueException) e;
} else if (e instanceof PermissionDeniedException) {
throw (PermissionDeniedException) e;
} else if (e instanceof InternalErrorException) {
throw (InternalErrorException) e;
}
}
}
public void deleteRule(long ruleId, long userId, long accountId) throws InvalidParameterValueException, PermissionDeniedException, InternalErrorException
{
_networkMgr.deleteRule(ruleId, userId, accountId);
}
public long deleteRuleAsync(long id, long userId, long accountId) {

View File

@ -119,6 +119,7 @@ import com.cloud.network.dao.SecurityGroupVMMapDao;
import com.cloud.network.security.NetworkGroupManager;
import com.cloud.network.security.NetworkGroupVO;
import com.cloud.pricing.dao.PricingDao;
import com.cloud.server.ManagementServer;
import com.cloud.service.ServiceOffering;
import com.cloud.service.ServiceOfferingVO;
import com.cloud.service.ServiceOffering.GuestIpType;
@ -153,6 +154,7 @@ import com.cloud.storage.snapshot.SnapshotManager;
import com.cloud.user.AccountManager;
import com.cloud.user.AccountVO;
import com.cloud.user.User;
import com.cloud.user.UserContext;
import com.cloud.user.UserVO;
import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.UserDao;
@ -224,7 +226,6 @@ public class UserVmManagerImpl implements UserVmManager {
@Inject NetworkGroupManager _networkGroupManager;
@Inject ServiceOfferingDao _serviceOfferingDao;
@Inject EventDao _eventDao = null;
private IpAddrAllocator _IpAllocator;
ScheduledExecutorService _executor = null;
int _expungeInterval;
@ -1938,7 +1939,9 @@ public class UserVmManagerImpl implements UserVmManager {
public void expunge() {
List<UserVmVO> vms = _vmDao.findDestroyedVms(new Date(System.currentTimeMillis() - ((long)_expungeDelay << 10)));
s_logger.info("Found " + vms.size() + " vms to expunge.");
for (UserVmVO vm : vms) {
for (UserVmVO vm : vms)
{
String privateIpAddress = vm.getPrivateIpAddress();
long vmId = vm.getId();
releaseGuestIpAddress(vm);
vm.setGuestNetmask(null);
@ -1947,6 +1950,23 @@ public class UserVmManagerImpl implements UserVmManager {
s_logger.info("vm " + vmId + " is skipped because it is no longer in Destroyed state");
continue;
}
List<FirewallRuleVO> forwardingRules = null;
try
{
forwardingRules = _rulesDao.listByPrivateIp(privateIpAddress);
for(FirewallRuleVO rule: forwardingRules)
{
_networkMgr.deleteRule(rule.getId(), Long.valueOf(User.UID_SYSTEM), vm.getAccountId());
if(s_logger.isDebugEnabled())
s_logger.debug("Rule "+rule.getId()+" for vm:"+vm.getId()+" is deleted successfully during expunge operation");
}
} catch (Exception e) {
s_logger.info("VM " + vmId +" expunge failed due to " + e.getMessage());
}
List<VolumeVO> vols = null;
try {