VPC: set networkId to be null for IP address when the last PF/LB rule is removed for it and the IP belongs to VPC

Conflicts:

	server/src/com/cloud/network/rules/RulesManagerImpl.java
This commit is contained in:
Alena Prokharchyk 2012-06-29 13:35:44 -07:00
parent 8d16d7f94f
commit 2dc1a286f6
6 changed files with 157 additions and 83 deletions

View File

@ -425,7 +425,8 @@ public class FirewallManagerImpl implements FirewallService, FirewallManager, Ma
}
@DB
protected void removeRule(FirewallRule rule) {
@Override
public void removeRule(FirewallRule rule) {
Transaction txn = Transaction.currentTxn();
txn.start();
@ -527,7 +528,7 @@ public class FirewallManagerImpl implements FirewallService, FirewallManager, Ma
if (s_logger.isDebugEnabled()) {
s_logger.debug("Found a rule that is still in stage state so just removing it: " + rule);
}
_firewallDao.remove(rule.getId());
removeRule(rule);
generateUsageEvent = true;
} else if (rule.getState() == State.Add || rule.getState() == State.Active) {
rule.setState(State.Revoke);

View File

@ -675,7 +675,7 @@ public class LoadBalancingRulesManagerImpl<Type> implements LoadBalancingRulesMa
s_logger.warn("Unable to remove firewall rule id=" + lb.getId() + " as it has related firewall rule id=" + relatedRule.getId() + "; leaving it in Revoke state");
success = false;
} else {
_firewallDao.remove(lb.getId());
_firewallMgr.removeRule(lb);
}
_elbMgr.handleDeleteLoadBalancerRule(lb, callerUserId, caller);
@ -720,6 +720,7 @@ public class LoadBalancingRulesManagerImpl<Type> implements LoadBalancingRulesMa
}
LoadBalancer result = _elbMgr.handleCreateLoadBalancerRule(lb, lbOwner, lb.getNetworkId());
boolean performedIpAssoc = false;
if (result == null) {
IpAddress ip = null;
Network guestNetwork = _networkMgr.getNetwork(lb.getNetworkId());
@ -732,8 +733,13 @@ public class LoadBalancingRulesManagerImpl<Type> implements LoadBalancingRulesMa
try {
if (ipAddressVO != null) {
if (ipAddressVO.getAssociatedWithNetworkId() == null) {
//set networkId just for verification purposes
ipAddressVO.setAssociatedWithNetworkId(lb.getNetworkId());
_networkMgr.checkIpForService(ipAddressVO, Service.Lb);
s_logger.debug("The ip is not associated with the network id="+ lb.getNetworkId() + " so assigning");
ipAddressVO = _networkMgr.associateIPToGuestNetwork(ipAddrId, lb.getNetworkId());
boolean perfomedIpAssoc = true;
}
_networkMgr.checkIpForService(ipAddressVO, Service.Lb);
}
@ -752,6 +758,15 @@ public class LoadBalancingRulesManagerImpl<Type> implements LoadBalancingRulesMa
s_logger.debug("Releasing system IP address " + ip + " as corresponding lb rule failed to create");
_networkMgr.handleSystemIpRelease(ip);
}
// release ip address if ipassoc was perfored
if (performedIpAssoc) {
//if the rule is the last one for the ip address assigned to VPC, unassign it from the network
ip = _ipAddressDao.findById(ip.getId());
if (ip != null && ip.getVpcId() != null && _firewallDao.listByIp(ip.getId()).isEmpty()) {
s_logger.debug("Releasing VPC ip address " + ip + " as LB rule failed to create");
_networkMgr.unassignIPFromVpcNetwork(ip.getId());
}
}
}
}
@ -771,7 +786,6 @@ public class LoadBalancingRulesManagerImpl<Type> implements LoadBalancingRulesMa
long sourceIpId = lb.getSourceIpAddressId();
IPAddressVO ipAddr = _ipAddressDao.findById(sourceIpId);
Long networkId = ipAddr.getSourceNetworkId();
// make sure ip address exists
if (ipAddr == null || !ipAddr.readyToUse()) {
InvalidParameterValueException ex = new InvalidParameterValueException("Unable to create load balancer rule, invalid IP address id specified");
@ -786,7 +800,7 @@ public class LoadBalancingRulesManagerImpl<Type> implements LoadBalancingRulesMa
_firewallMgr.validateFirewallRule(caller.getCaller(), ipAddr, srcPortStart, srcPortEnd, lb.getProtocol(),
Purpose.LoadBalancing, FirewallRuleType.User);
networkId = ipAddr.getAssociatedWithNetworkId();
Long networkId = ipAddr.getAssociatedWithNetworkId();
if (networkId == null) {
InvalidParameterValueException ex = new InvalidParameterValueException("Unable to create load balancer rule ; specified sourceip id is not associated with any network");
ex.addProxyObject(ipAddr, sourceIpId, "sourceIpId");
@ -842,7 +856,7 @@ public class LoadBalancingRulesManagerImpl<Type> implements LoadBalancingRulesMa
txn.start();
_firewallMgr.revokeRelatedFirewallRule(newRule.getId(), false);
_lbDao.remove(newRule.getId());
removeLBRule(newRule);
txn.commit();
}
@ -897,7 +911,7 @@ public class LoadBalancingRulesManagerImpl<Type> implements LoadBalancingRulesMa
boolean checkForReleaseElasticIp = false;
txn.start();
if (lb.getState() == FirewallRule.State.Revoke) {
_lbDao.remove(lb.getId());
removeLBRule(lb);
s_logger.debug("LB " + lb.getId() + " is successfully removed");
checkForReleaseElasticIp = true;
} else if (lb.getState() == FirewallRule.State.Add) {
@ -1290,4 +1304,17 @@ public class LoadBalancingRulesManagerImpl<Type> implements LoadBalancingRulesMa
return _lbDao.findById(lbId);
}
@DB
protected void removeLBRule(LoadBalancerVO rule) {
Transaction txn = Transaction.currentTxn();
txn.start();
_lbDao.remove(rule.getId());
//if the rule is the last one for the ip address assigned to VPC, unassign it from the network
IpAddress ip = _ipAddressDao.findById(rule.getSourceIpAddressId());
if (ip != null && ip.getVpcId() != null && _firewallDao.listByIp(ip.getId()).isEmpty()) {
_networkMgr.unassignIPFromVpcNetwork(ip.getId());
}
txn.commit();
}
}

View File

@ -310,6 +310,15 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian
NicProfile publicNic = _itMgr.addVmToNetwork(router, publicNetwork, defaultNic);
//setup public network
if (publicNic != null) {
if (ipAddress.isSourceNat()) {
if (router.getPublicIpAddress() == null) {
DomainRouterVO routerVO = _routerDao.findById(router.getId());
routerVO.setPublicIpAddress(ipAddress.getAddress().toString());
routerVO.setPublicNetmask(ipAddress.getNetmask());
routerVO.setPublicMacAddress(ipAddress.getMacAddress());
_routerDao.update(routerVO.getId(), routerVO);
}
}
publicNic.setDefaultNic(true);
if (ipAddress != null) {
IPAddressVO ipVO = _ipAddressDao.findById(ipAddress.getId());

View File

@ -76,4 +76,9 @@ public interface FirewallManager extends FirewallService {
boolean addSystemFirewallRules(IPAddressVO ip, Account acct);
/**
* @param rule
*/
void removeRule(FirewallRule rule);
}

View File

@ -173,92 +173,113 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager {
Long networkId = rule.getNetworkId();
//associate ip address to network (if needed)
boolean performedIpAssoc = false;
if (ipAddress.getAssociatedWithNetworkId() == null) {
//set networkId just for verification purposes
ipAddress.setAssociatedWithNetworkId(networkId);
_networkMgr.checkIpForService(ipAddress, Service.PortForwarding);
s_logger.debug("The ip is not associated with the network id="+ networkId + " so assigning");
try {
ipAddress = _networkMgr.associateIPToGuestNetwork(ipAddrId, networkId);
performedIpAssoc = true;
} catch (Exception ex) {
throw new CloudRuntimeException("Failed to associate ip to network as " +
"a part of port forwarding rule creation");
}
} else {
_networkMgr.checkIpForService(ipAddress, Service.PortForwarding);
}
_networkMgr.checkIpForService(ipAddress, Service.PortForwarding);
_firewallMgr.validateFirewallRule(caller, ipAddress, rule.getSourcePortStart(), rule.getSourcePortEnd(),
rule.getProtocol(), Purpose.PortForwarding, FirewallRuleType.User);
Long accountId = ipAddress.getAllocatedToAccountId();
Long domainId = ipAddress.getAllocatedInDomainId();
// start port can't be bigger than end port
if (rule.getDestinationPortStart() > rule.getDestinationPortEnd()) {
throw new InvalidParameterValueException("Start port can't be bigger than end port");
}
// check that the port ranges are of equal size
if ((rule.getDestinationPortEnd() - rule.getDestinationPortStart()) != (rule.getSourcePortEnd() - rule.getSourcePortStart())) {
throw new InvalidParameterValueException("Source port and destination port ranges should be of equal sizes.");
}
// validate user VM exists
UserVm vm = _vmDao.findById(vmId);
if (vm == null) {
throw new InvalidParameterValueException("Unable to create port forwarding rule on address " + ipAddress +
", invalid virtual machine id specified (" + vmId + ").");
} else {
checkRuleAndUserVm(rule, vm, caller);
}
// Verify that vm has nic in the network
Ip dstIp = rule.getDestinationIpAddress();
Nic guestNic = _networkMgr.getNicInNetwork(vmId, networkId);
if (guestNic == null || guestNic.getIp4Address() == null) {
throw new InvalidParameterValueException("Vm doesn't belong to network associated with ipAddress");
} else {
dstIp = new Ip(guestNic.getIp4Address());
}
Transaction txn = Transaction.currentTxn();
txn.start();
PortForwardingRuleVO newRule = new PortForwardingRuleVO(rule.getXid(), rule.getSourceIpAddressId(),
rule.getSourcePortStart(), rule.getSourcePortEnd(), dstIp, rule.getDestinationPortStart(),
rule.getDestinationPortEnd(), rule.getProtocol().toLowerCase(), networkId, accountId, domainId, vmId);
newRule = _portForwardingDao.persist(newRule);
// create firewallRule for 0.0.0.0/0 cidr
if (openFirewall) {
_firewallMgr.createRuleForAllCidrs(ipAddrId, caller, rule.getSourcePortStart(), rule.getSourcePortEnd(),
rule.getProtocol(), null, null, newRule.getId(), networkId);
}
try {
_firewallMgr.detectRulesConflict(newRule);
if (!_firewallDao.setStateToAdd(newRule)) {
throw new CloudRuntimeException("Unable to update the state to add for " + newRule);
}
UserContext.current().setEventDetails("Rule Id: " + newRule.getId());
UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NET_RULE_ADD, newRule.getAccountId(),
ipAddress.getDataCenterId(), newRule.getId(), null);
_usageEventDao.persist(usageEvent);
txn.commit();
return newRule;
} catch (Exception e) {
if (newRule != null) {
txn.start();
// no need to apply the rule as it wasn't programmed on the backend yet
_firewallMgr.revokeRelatedFirewallRule(newRule.getId(), false);
_portForwardingDao.remove(newRule.getId());
txn.commit();
_firewallMgr.validateFirewallRule(caller, ipAddress, rule.getSourcePortStart(), rule.getSourcePortEnd(),
rule.getProtocol(), Purpose.PortForwarding, FirewallRuleType.User);
Long accountId = ipAddress.getAllocatedToAccountId();
Long domainId = ipAddress.getAllocatedInDomainId();
// start port can't be bigger than end port
if (rule.getDestinationPortStart() > rule.getDestinationPortEnd()) {
throw new InvalidParameterValueException("Start port can't be bigger than end port");
}
if (e instanceof NetworkRuleConflictException) {
throw (NetworkRuleConflictException) e;
// check that the port ranges are of equal size
if ((rule.getDestinationPortEnd() - rule.getDestinationPortStart()) != (rule.getSourcePortEnd() - rule.getSourcePortStart())) {
throw new InvalidParameterValueException("Source port and destination port ranges should be of equal sizes.");
}
// validate user VM exists
UserVm vm = _vmDao.findById(vmId);
if (vm == null) {
throw new InvalidParameterValueException("Unable to create port forwarding rule on address " + ipAddress +
", invalid virtual machine id specified (" + vmId + ").");
} else {
checkRuleAndUserVm(rule, vm, caller);
}
// Verify that vm has nic in the network
Ip dstIp = rule.getDestinationIpAddress();
Nic guestNic = _networkMgr.getNicInNetwork(vmId, networkId);
if (guestNic == null || guestNic.getIp4Address() == null) {
throw new InvalidParameterValueException("Vm doesn't belong to network associated with ipAddress");
} else {
dstIp = new Ip(guestNic.getIp4Address());
}
Transaction txn = Transaction.currentTxn();
txn.start();
PortForwardingRuleVO newRule = new PortForwardingRuleVO(rule.getXid(), rule.getSourceIpAddressId(),
rule.getSourcePortStart(), rule.getSourcePortEnd(), dstIp, rule.getDestinationPortStart(),
rule.getDestinationPortEnd(), rule.getProtocol().toLowerCase(), networkId, accountId, domainId, vmId);
newRule = _portForwardingDao.persist(newRule);
// create firewallRule for 0.0.0.0/0 cidr
if (openFirewall) {
_firewallMgr.createRuleForAllCidrs(ipAddrId, caller, rule.getSourcePortStart(), rule.getSourcePortEnd(),
rule.getProtocol(), null, null, newRule.getId(), networkId);
}
try {
_firewallMgr.detectRulesConflict(newRule);
if (!_firewallDao.setStateToAdd(newRule)) {
throw new CloudRuntimeException("Unable to update the state to add for " + newRule);
}
UserContext.current().setEventDetails("Rule Id: " + newRule.getId());
UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NET_RULE_ADD, newRule.getAccountId(),
ipAddress.getDataCenterId(), newRule.getId(), null);
_usageEventDao.persist(usageEvent);
txn.commit();
return newRule;
} catch (Exception e) {
if (newRule != null) {
txn.start();
// no need to apply the rule as it wasn't programmed on the backend yet
_firewallMgr.revokeRelatedFirewallRule(newRule.getId(), false);
removePFRule(newRule);
txn.commit();
}
if (e instanceof NetworkRuleConflictException) {
throw (NetworkRuleConflictException) e;
}
throw new CloudRuntimeException("Unable to add rule for the ip id=" + ipAddrId, e);
}
} finally {
// release ip address if ipassoc was perfored
if (performedIpAssoc) {
//if the rule is the last one for the ip address assigned to VPC, unassign it from the network
IpAddress ip = _ipAddressDao.findById(ipAddress.getId());
if (ip != null && ip.getVpcId() != null && _firewallDao.listByIp(ip.getId()).isEmpty()) {
s_logger.debug("Releasing VPC ip address " + ip + " as PF rule failed to create");
_networkMgr.unassignIPFromVpcNetwork(ip.getId());
}
}
throw new CloudRuntimeException("Unable to add rule for the ip id=" + ipAddrId, e);
}
}
@Override
@ -326,7 +347,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager {
txn.start();
// no need to apply the rule as it wasn't programmed on the backend yet
_firewallMgr.revokeRelatedFirewallRule(newRule.getId(), false);
_portForwardingDao.remove(newRule.getId());
_firewallMgr.removeRule(newRule);
txn.commit();
}
@ -1017,7 +1038,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager {
txn.start();
for (FirewallRuleVO newRule : rules) {
_portForwardingDao.remove(newRule.getId());
_firewallMgr.removeRule(newRule);
}
txn.commit();
}
@ -1271,4 +1292,18 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager {
}
}
}
@DB
protected void removePFRule(PortForwardingRuleVO rule) {
Transaction txn = Transaction.currentTxn();
txn.start();
_portForwardingDao.remove(rule.getId());
//if the rule is the last one for the ip address assigned to VPC, unassign it from the network
IpAddress ip = _ipAddressDao.findById(rule.getSourceIpAddressId());
if (ip != null && ip.getVpcId() != null && _firewallDao.listByIp(ip.getId()).isEmpty()) {
_networkMgr.unassignIPFromVpcNetwork(ip.getId());
}
txn.commit();
}
}

View File

@ -16,8 +16,6 @@ import java.util.List;
import javax.ejb.Local;
import org.apache.log4j.Logger;
import com.cloud.network.dao.FirewallRulesCidrsDaoImpl;
import com.cloud.network.rules.FirewallRule.Purpose;
import com.cloud.network.rules.FirewallRule.State;
@ -30,7 +28,6 @@ import com.cloud.utils.db.SearchCriteria.Op;
@Local(value=PortForwardingRulesDao.class)
public class PortForwardingRulesDaoImpl extends GenericDaoBase<PortForwardingRuleVO, Long> implements PortForwardingRulesDao {
private static final Logger s_logger = Logger.getLogger(PortForwardingRulesDaoImpl.class);
protected final SearchBuilder<PortForwardingRuleVO> AllFieldsSearch;
protected final SearchBuilder<PortForwardingRuleVO> ApplicationSearch;