diff --git a/api/src/com/cloud/api/commands/AssociateIPAddrCmd.java b/api/src/com/cloud/api/commands/AssociateIPAddrCmd.java index 7a072577d7f..15c596be8cd 100644 --- a/api/src/com/cloud/api/commands/AssociateIPAddrCmd.java +++ b/api/src/com/cloud/api/commands/AssociateIPAddrCmd.java @@ -37,6 +37,7 @@ import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.IpAddress; import com.cloud.network.Network; +import com.cloud.network.vpc.Vpc; import com.cloud.user.Account; import com.cloud.user.UserContext; @@ -49,24 +50,34 @@ public class AssociateIPAddrCmd extends BaseAsyncCreateCmd { //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// - @Parameter(name=ApiConstants.ACCOUNT, type=CommandType.STRING, description="the account to associate with this IP address") + @Parameter(name=ApiConstants.ACCOUNT, type=CommandType.STRING, + description="the account to associate with this IP address") private String accountName; @IdentityMapper(entityTableName="domain") - @Parameter(name=ApiConstants.DOMAIN_ID, type=CommandType.LONG, description="the ID of the domain to associate with this IP address") + @Parameter(name=ApiConstants.DOMAIN_ID, type=CommandType.LONG, + description="the ID of the domain to associate with this IP address") private Long domainId; @IdentityMapper(entityTableName="data_center") - @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.LONG, description="the ID of the availability zone you want to acquire an public IP address from") + @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.LONG, + description="the ID of the availability zone you want to acquire an public IP address from") private Long zoneId; @IdentityMapper(entityTableName="networks") - @Parameter(name=ApiConstants.NETWORK_ID, type=CommandType.LONG, description="The network this ip address should be associated to.") + @Parameter(name=ApiConstants.NETWORK_ID, type=CommandType.LONG, + description="The network this ip address should be associated to.") private Long networkId; @IdentityMapper(entityTableName="projects") - @Parameter(name=ApiConstants.PROJECT_ID, type=CommandType.LONG, description="Deploy vm for the project") + @Parameter(name=ApiConstants.PROJECT_ID, type=CommandType.LONG, + description="Deploy vm for the project") private Long projectId; + + @IdentityMapper(entityTableName="vpc") + @Parameter(name=ApiConstants.VPC_ID, type=CommandType.LONG, description="the VPC you want the ip address to " + + "be associated with") + private Long vpcId; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -90,18 +101,40 @@ public class AssociateIPAddrCmd extends BaseAsyncCreateCmd { return UserContext.current().getCaller().getDomainId(); } - private Long getZoneId() { - return zoneId; + private long getZoneId() { + if (zoneId != null) { + return zoneId; + } else if (vpcId != null) { + Vpc vpc = _entityMgr.findById(Vpc.class, vpcId); + if (vpc != null) { + return vpc.getZoneId(); + } + } else if (networkId != null) { + Network ntwk = _entityMgr.findById(Network.class, networkId); + if (ntwk != null) { + return ntwk.getDataCenterId(); + } + } + + throw new InvalidParameterValueException("Unable to figure out zone to assign ip to"); + } + + public Long getVpcId() { + return vpcId; } public Long getNetworkId() { + if (vpcId != null) { + return null; + } + if (networkId != null) { return networkId; } Long zoneId = getZoneId(); if (zoneId == null) { - throw new InvalidParameterValueException("Either networkId or zoneId has to be specified"); + return null; } DataCenter zone = _configService.getZone(zoneId); @@ -110,7 +143,8 @@ public class AssociateIPAddrCmd extends BaseAsyncCreateCmd { _accountService.getAccount(getEntityOwnerId())); if (networks.size() == 0) { String domain = _domainService.getDomain(getDomainId()).getName(); - throw new InvalidParameterValueException("Account name=" + getAccountName() + " domain=" + domain + " doesn't have virtual networks in zone=" + zone.getName()); + throw new InvalidParameterValueException("Account name=" + getAccountName() + " domain=" + domain + + " doesn't have virtual networks in zone=" + zone.getName()); } if (networks.size() < 1) { @@ -123,7 +157,8 @@ public class AssociateIPAddrCmd extends BaseAsyncCreateCmd { } else { Network defaultGuestNetwork = _networkService.getExclusiveGuestNetwork(zoneId); if (defaultGuestNetwork == null) { - throw new InvalidParameterValueException("Unable to find a default Guest network for account " + getAccountName() + " in domain id=" + getDomainId()); + throw new InvalidParameterValueException("Unable to find a default Guest network for account " + + getAccountName() + " in domain id=" + getDomainId()); } else { return defaultGuestNetwork.getId(); } @@ -169,7 +204,8 @@ public class AssociateIPAddrCmd extends BaseAsyncCreateCmd { @Override public void create() throws ResourceAllocationException{ try { - IpAddress ip = _networkService.allocateIP(getNetworkId(), _accountService.getAccount(getEntityOwnerId()), false); + IpAddress ip = _networkService.allocateIP(_accountService.getAccount(getEntityOwnerId()), false, getZoneId()); + if (ip != null) { this.setEntityId(ip.getId()); } else { @@ -186,9 +222,16 @@ public class AssociateIPAddrCmd extends BaseAsyncCreateCmd { } @Override - public void execute() throws ResourceUnavailableException, ResourceAllocationException, ConcurrentOperationException, InsufficientCapacityException { + public void execute() throws ResourceUnavailableException, ResourceAllocationException, + ConcurrentOperationException, InsufficientCapacityException { UserContext.current().setEventDetails("Ip Id: " + getEntityId()); - IpAddress result = _networkService.associateIP(getEntityId()); + + IpAddress result = null; + + if (getVpcId() != null) { + result = _networkService.associateIP(getEntityId(), getNetworkId(), getVpcId()); + } + if (result != null) { IPAddressResponse ipResponse = _responseGenerator.createIPAddressResponse(result); ipResponse.setResponseName(getCommandName()); diff --git a/api/src/com/cloud/api/commands/CreateFirewallRuleCmd.java b/api/src/com/cloud/api/commands/CreateFirewallRuleCmd.java index 24093d6be48..14ba4f3ab28 100644 --- a/api/src/com/cloud/api/commands/CreateFirewallRuleCmd.java +++ b/api/src/com/cloud/api/commands/CreateFirewallRuleCmd.java @@ -72,6 +72,11 @@ public class CreateFirewallRuleCmd extends BaseAsyncCreateCmd implements Firewal @Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, description = "type of firewallrule: system/user") private String type; + @IdentityMapper(entityTableName="networks") + @Parameter(name=ApiConstants.NETWORK_ID, type=CommandType.LONG, + description="The network of the vm the Firewall rule will be created for") + private Long networkId; + // /////////////////////////////////////////////////// // ///////////////// Accessors /////////////////////// // /////////////////////////////////////////////////// @@ -187,7 +192,19 @@ public class CreateFirewallRuleCmd extends BaseAsyncCreateCmd implements Firewal @Override public long getNetworkId() { - throw new UnsupportedOperationException("Not yet implemented"); + IpAddress ip = _entityMgr.findById(IpAddress.class, getIpAddressId()); + Long ntwkId = null; + + if (ip.getAssociatedWithNetworkId() != null) { + ntwkId = ip.getAssociatedWithNetworkId(); + } else { + ntwkId = networkId; + } + if (ntwkId == null) { + throw new InvalidParameterValueException("Unable to create firewall rule for the ipAddress id=" + ipAddressId + + " as ip is not associated with any network and no networkId is passed in"); + } + return ntwkId; } @Override diff --git a/api/src/com/cloud/api/commands/CreateLoadBalancerRuleCmd.java b/api/src/com/cloud/api/commands/CreateLoadBalancerRuleCmd.java index 0c052d3422a..b4aed0b68c3 100644 --- a/api/src/com/cloud/api/commands/CreateLoadBalancerRuleCmd.java +++ b/api/src/com/cloud/api/commands/CreateLoadBalancerRuleCmd.java @@ -167,9 +167,12 @@ public class CreateLoadBalancerRuleCmd extends BaseAsyncCreateCmd /*implements } } else { IpAddress ipAddr = _networkService.getIp(publicIpId); - return ipAddr.getAssociatedWithNetworkId(); + if (ipAddr.getAssociatedWithNetworkId() != null) { + return ipAddr.getAssociatedWithNetworkId(); + } else { + throw new InvalidParameterValueException("Ip address id=" + publicIpId + " is not associated with any network"); + } } - } public Integer getPublicPort() { diff --git a/api/src/com/cloud/api/commands/CreatePortForwardingRuleCmd.java b/api/src/com/cloud/api/commands/CreatePortForwardingRuleCmd.java index 8acd1e18764..8bf3af82c2f 100644 --- a/api/src/com/cloud/api/commands/CreatePortForwardingRuleCmd.java +++ b/api/src/com/cloud/api/commands/CreatePortForwardingRuleCmd.java @@ -47,27 +47,40 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P // /////////////////////////////////////////////////// @IdentityMapper(entityTableName = "user_ip_address") - @Parameter(name = ApiConstants.IP_ADDRESS_ID, type = CommandType.LONG, required = true, description = "the IP address id of the port forwarding rule") + @Parameter(name = ApiConstants.IP_ADDRESS_ID, type = CommandType.LONG, required = true, + description = "the IP address id of the port forwarding rule") private Long ipAddressId; - @Parameter(name = ApiConstants.PRIVATE_START_PORT, type = CommandType.INTEGER, required = true, description = "the starting port of port forwarding rule's private port range") + @Parameter(name = ApiConstants.PRIVATE_START_PORT, type = CommandType.INTEGER, required = true, + description = "the starting port of port forwarding rule's private port range") private Integer privateStartPort; - @Parameter(name = ApiConstants.PROTOCOL, type = CommandType.STRING, required = true, description = "the protocol for the port fowarding rule. Valid values are TCP or UDP.") + @Parameter(name = ApiConstants.PROTOCOL, type = CommandType.STRING, required = true, + description = "the protocol for the port fowarding rule. Valid values are TCP or UDP.") private String protocol; - @Parameter(name = ApiConstants.PUBLIC_START_PORT, type = CommandType.INTEGER, required = true, description = "the starting port of port forwarding rule's public port range") + @Parameter(name = ApiConstants.PUBLIC_START_PORT, type = CommandType.INTEGER, required = true, + description = "the starting port of port forwarding rule's public port range") private Integer publicStartPort; @IdentityMapper(entityTableName = "vm_instance") - @Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID, type = CommandType.LONG, required = true, description = "the ID of the virtual machine for the port forwarding rule") + @Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID, type = CommandType.LONG, required = true, + description = "the ID of the virtual machine for the port forwarding rule") private Long virtualMachineId; - @Parameter(name = ApiConstants.CIDR_LIST, type = CommandType.LIST, collectionType = CommandType.STRING, description = "the cidr list to forward traffic from") + @Parameter(name = ApiConstants.CIDR_LIST, type = CommandType.LIST, collectionType = CommandType.STRING, + description = "the cidr list to forward traffic from") private List cidrlist; - @Parameter(name = ApiConstants.OPEN_FIREWALL, type = CommandType.BOOLEAN, description = "if true, firewall rule for source/end pubic port is automatically created; if false - firewall rule has to be created explicitely. Has value true by default") + @Parameter(name = ApiConstants.OPEN_FIREWALL, type = CommandType.BOOLEAN, + description = "if true, firewall rule for source/end pubic port is automatically created; " + + "if false - firewall rule has to be created explicitely. Has value true by default") private Boolean openFirewall; + + @IdentityMapper(entityTableName="networks") + @Parameter(name=ApiConstants.NETWORK_ID, type=CommandType.LONG, + description="The network of the vm the Port Forwarding rule will be created for") + private Long networkId; // /////////////////////////////////////////////////// // ///////////////// Accessors /////////////////////// @@ -93,7 +106,8 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P public List getSourceCidrList() { if (cidrlist != null) { - throw new InvalidParameterValueException("Parameter cidrList is deprecated; if you need to open firewall rule for the specific cidr, please refer to createFirewallRule command"); + throw new InvalidParameterValueException("Parameter cidrList is deprecated; if you need to open firewall " + + "rule for the specific cidr, please refer to createFirewallRule command"); } return null; } @@ -189,7 +203,19 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P @Override public long getNetworkId() { - throw new UnsupportedOperationException("Not yet implemented"); + IpAddress ip = _entityMgr.findById(IpAddress.class, getIpAddressId()); + Long ntwkId = null; + + if (ip.getAssociatedWithNetworkId() != null) { + ntwkId = ip.getAssociatedWithNetworkId(); + } else { + ntwkId = networkId; + } + if (ntwkId == null) { + throw new InvalidParameterValueException("Unable to create port forwarding rule for the ipAddress id=" + ipAddressId + + " as ip is not associated with any network and no networkId is passed in"); + } + return ntwkId; } @Override @@ -201,7 +227,7 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P } return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are -// tracked + // tracked } @Override @@ -232,7 +258,6 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P @Override public void create() { - // cidr list parameter is deprecated if (cidrlist != null) { throw new InvalidParameterValueException("Parameter cidrList is deprecated; if you need to open firewall rule for the specific cidr, please refer to createFirewallRule command"); diff --git a/api/src/com/cloud/api/commands/CreateRemoteAccessVpnCmd.java b/api/src/com/cloud/api/commands/CreateRemoteAccessVpnCmd.java index b6e13878f46..b783adf781a 100644 --- a/api/src/com/cloud/api/commands/CreateRemoteAccessVpnCmd.java +++ b/api/src/com/cloud/api/commands/CreateRemoteAccessVpnCmd.java @@ -58,6 +58,11 @@ public class CreateRemoteAccessVpnCmd extends BaseAsyncCreateCmd { @Parameter(name = ApiConstants.OPEN_FIREWALL, type = CommandType.BOOLEAN, description = "if true, firewall rule for source/end pubic port is automatically created; if false - firewall rule has to be created explicitely. Has value true by default") private Boolean openFirewall; + @IdentityMapper(entityTableName="networks") + @Parameter(name=ApiConstants.NETWORK_ID, type=CommandType.LONG, + description="The network of the ip the VPN be created for") + private Long networkId; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -125,10 +130,26 @@ public class CreateRemoteAccessVpnCmd extends BaseAsyncCreateCmd { return EventTypes.EVENT_REMOTE_ACCESS_VPN_CREATE; } + public long getNetworkId() { + IpAddress ip = _entityMgr.findById(IpAddress.class, getPublicIpId()); + Long ntwkId = null; + + if (ip.getAssociatedWithNetworkId() != null) { + ntwkId = ip.getAssociatedWithNetworkId(); + } else { + ntwkId = networkId; + } + if (ntwkId == null) { + throw new InvalidParameterValueException("Unable to create remote access vpn for the ipAddress id=" + getPublicIpId() + + " as ip is not associated with any network and no networkId is passed in"); + } + return ntwkId; + } + @Override public void create() { try { - RemoteAccessVpn vpn = _ravService.createRemoteAccessVpn(publicIpId, ipRange, getOpenFirewall()); + RemoteAccessVpn vpn = _ravService.createRemoteAccessVpn(publicIpId, ipRange, getOpenFirewall(), getNetworkId()); if (vpn != null) { this.setEntityId(vpn.getServerAddressId()); } else { diff --git a/api/src/com/cloud/api/commands/DisassociateIPAddrCmd.java b/api/src/com/cloud/api/commands/DisassociateIPAddrCmd.java index afdc7d7ff47..ea19ea319c6 100644 --- a/api/src/com/cloud/api/commands/DisassociateIPAddrCmd.java +++ b/api/src/com/cloud/api/commands/DisassociateIPAddrCmd.java @@ -41,7 +41,8 @@ public class DisassociateIPAddrCmd extends BaseAsyncCmd { ///////////////////////////////////////////////////// @IdentityMapper(entityTableName="user_ip_address") - @Parameter(name=ApiConstants.ID, type=CommandType.LONG, required=true, description="the id of the public ip address to disassociate") + @Parameter(name=ApiConstants.ID, type=CommandType.LONG, required=true, description="the id of the public ip address" + + " to disassociate") private Long id; // unexposed parameter needed for events logging @@ -67,8 +68,8 @@ public class DisassociateIPAddrCmd extends BaseAsyncCmd { @Override public void execute() throws InsufficientAddressCapacityException{ - UserContext.current().setEventDetails("Ip Id: "+getIpAddressId()); - boolean result = _networkService.disassociateIpAddress(id); + UserContext.current().setEventDetails("Ip Id: " + getIpAddressId()); + boolean result = _networkService.releaseIpAddress(getIpAddressId()); if (result) { SuccessResponse response = new SuccessResponse(getCommandName()); this.setResponseObject(response); diff --git a/api/src/com/cloud/api/commands/EnableStaticNatCmd.java b/api/src/com/cloud/api/commands/EnableStaticNatCmd.java index e62d963c097..b0106ad975c 100644 --- a/api/src/com/cloud/api/commands/EnableStaticNatCmd.java +++ b/api/src/com/cloud/api/commands/EnableStaticNatCmd.java @@ -21,8 +21,10 @@ 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.InvalidParameterValueException; import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.IpAddress; import com.cloud.user.Account; import com.cloud.uservm.UserVm; @@ -37,12 +39,19 @@ public class EnableStaticNatCmd extends BaseCmd{ ///////////////////////////////////////////////////// @IdentityMapper(entityTableName="user_ip_address") - @Parameter(name=ApiConstants.IP_ADDRESS_ID, type=CommandType.LONG, required=true, description="the public IP address id for which static nat feature is being enabled") + @Parameter(name=ApiConstants.IP_ADDRESS_ID, type=CommandType.LONG, required=true, description="the public IP " + + "address id for which static nat feature is being enabled") private Long ipAddressId; @IdentityMapper(entityTableName="vm_instance") - @Parameter(name=ApiConstants.VIRTUAL_MACHINE_ID, type=CommandType.LONG, required=true, description="the ID of the virtual machine for enabling static nat feature") + @Parameter(name=ApiConstants.VIRTUAL_MACHINE_ID, type=CommandType.LONG, required=true, description="the ID of " + + "the virtual machine for enabling static nat feature") private Long virtualMachineId; + + @IdentityMapper(entityTableName="networks") + @Parameter(name=ApiConstants.NETWORK_ID, type=CommandType.LONG, + description="The network of the vm the static nat will be enabled for.") + private Long networkId; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -55,6 +64,22 @@ public class EnableStaticNatCmd extends BaseCmd{ public Long getVirtualMachineId() { return virtualMachineId; } + + public long getNetworkId() { + IpAddress ip = _entityMgr.findById(IpAddress.class, getIpAddressId()); + Long ntwkId = null; + + if (ip.getAssociatedWithNetworkId() != null) { + ntwkId = ip.getAssociatedWithNetworkId(); + } else { + ntwkId = networkId; + } + if (ntwkId == null) { + throw new InvalidParameterValueException("Unable to enable static nat for the ipAddress id=" + ipAddressId + + " as ip is not associated with any network and no networkId is passed in"); + } + return ntwkId; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// @@ -78,7 +103,7 @@ public class EnableStaticNatCmd extends BaseCmd{ @Override public void execute() throws ResourceUnavailableException{ try { - boolean result = _rulesService.enableStaticNat(ipAddressId, virtualMachineId); + boolean result = _rulesService.enableStaticNat(ipAddressId, virtualMachineId, getNetworkId()); if (result) { SuccessResponse response = new SuccessResponse(getCommandName()); this.setResponseObject(response); diff --git a/api/src/com/cloud/network/NetworkService.java b/api/src/com/cloud/network/NetworkService.java index 200aebfea69..5eb57130869 100755 --- a/api/src/com/cloud/network/NetworkService.java +++ b/api/src/com/cloud/network/NetworkService.java @@ -37,22 +37,10 @@ public interface NetworkService { List getIsolatedNetworksOwnedByAccountInZone(long zoneId, Account owner); - IpAddress allocateIP(long networkId, Account ipOwner, boolean isSystem) throws ResourceAllocationException, - InsufficientAddressCapacityException, ConcurrentOperationException; + IpAddress allocateIP(Account ipOwner, boolean isSystem, long zoneId) throws ResourceAllocationException, + InsufficientAddressCapacityException, ConcurrentOperationException; - /** - * Associates a public IP address for a router. - * - * @param ipId - * - the command specifying ipAddress - * @return ip address object - * @throws ResourceAllocationException - * , InsufficientCapacityException - */ - IpAddress associateIP(long ipId) throws ResourceAllocationException, InsufficientAddressCapacityException, - ConcurrentOperationException, ResourceUnavailableException; - - boolean disassociateIpAddress(long ipAddressId) throws InsufficientAddressCapacityException; + boolean releaseIpAddress(long ipAddressId) throws InsufficientAddressCapacityException; Network createGuestNetwork(CreateNetworkCmd cmd) throws InsufficientCapacityException, ConcurrentOperationException, ResourceAllocationException; @@ -144,4 +132,18 @@ public interface NetworkService { List listNetworksByVpc(long vpcId); boolean isVmPartOfNetwork(long vmId, long ntwkId); + + /** + * @param entityId + * @param networkId + * @param vpcId + * @return + * @throws ConcurrentOperationException + * @throws ResourceUnavailableException + * @throws ResourceAllocationException + * @throws InsufficientAddressCapacityException + */ + IpAddress associateIP(long ipId, Long networkId, Long vpcId) throws InsufficientAddressCapacityException, + ResourceAllocationException, ResourceUnavailableException, ConcurrentOperationException; + } diff --git a/api/src/com/cloud/network/rules/RulesService.java b/api/src/com/cloud/network/rules/RulesService.java index 137c10c35fc..60cc7b37fcf 100644 --- a/api/src/com/cloud/network/rules/RulesService.java +++ b/api/src/com/cloud/network/rules/RulesService.java @@ -60,7 +60,7 @@ public interface RulesService { boolean applyPortForwardingRules(long ipAdddressId, Account caller) throws ResourceUnavailableException; - boolean enableStaticNat(long ipAddressId, long vmId) throws NetworkRuleConflictException, ResourceUnavailableException; + boolean enableStaticNat(long ipAddressId, long vmId, long networkId) throws NetworkRuleConflictException, ResourceUnavailableException; PortForwardingRule getPortForwardigRule(long ruleId); diff --git a/api/src/com/cloud/network/vpn/RemoteAccessVpnService.java b/api/src/com/cloud/network/vpn/RemoteAccessVpnService.java index 3a50d7466d1..ba9540480f8 100644 --- a/api/src/com/cloud/network/vpn/RemoteAccessVpnService.java +++ b/api/src/com/cloud/network/vpn/RemoteAccessVpnService.java @@ -23,7 +23,7 @@ import com.cloud.network.VpnUser; public interface RemoteAccessVpnService { - RemoteAccessVpn createRemoteAccessVpn(long vpnServerAddressId, String ipRange, boolean openFirewall) throws NetworkRuleConflictException; + RemoteAccessVpn createRemoteAccessVpn(long vpnServerAddressId, String ipRange, boolean openFirewall, long networkId) throws NetworkRuleConflictException; void destroyRemoteAccessVpn(long vpnServerAddressId) throws ResourceUnavailableException; RemoteAccessVpn startRemoteAccessVpn(long vpnServerAddressId, boolean openFirewall) throws ResourceUnavailableException; diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index 1e7d09017cd..16c8e514756 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -2487,7 +2487,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura " as ip " + ip + " belonging to the range has firewall rules applied. Cleanup the rules first"); } //release public ip address here - success = success && _networkMgr.releasePublicIpAddress(ip.getId(), userId, caller); + success = success && _networkMgr.disassociatePublicIpAddress(ip.getId(), userId, caller); } if (!success) { s_logger.warn("Some ip addresses failed to be released as a part of vlan " + vlanDbId + " removal"); diff --git a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java index 3ad8c339350..1acba8ba7b6 100644 --- a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java +++ b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java @@ -512,7 +512,7 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase // release the public & private IP back to dc pool, as the load balancer // appliance is now destroyed _dcDao.releasePrivateIpAddress(lbIP, guestConfig.getDataCenterId(), null); - _networkMgr.releasePublicIpAddress(publicIp.getId(), _accountMgr.getSystemUser().getId(), _accountMgr.getSystemAccount()); + _networkMgr.disassociatePublicIpAddress(publicIp.getId(), _accountMgr.getSystemUser().getId(), _accountMgr.getSystemAccount()); } } catch (Exception e) { s_logger.warn("Failed to destroy load balancer appliance created for the network" + guestConfig.getId() + " due to " + e.getMessage()); @@ -664,7 +664,7 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase // release the public IP allocated for this LB appliance DetailVO publicIpDetail = _hostDetailDao.findDetail(lbHost.getId(), "publicip"); IPAddressVO ipVo = _ipAddressDao.findByIpAndDcId(guestConfig.getDataCenterId(), publicIpDetail.toString()); - _networkMgr.releasePublicIpAddress(ipVo.getId(), _accountMgr.getSystemUser().getId(), _accountMgr.getSystemAccount()); + _networkMgr.disassociatePublicIpAddress(ipVo.getId(), _accountMgr.getSystemUser().getId(), _accountMgr.getSystemAccount()); } else { deviceMapLock.unlock(); } diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index cdfa9aaeca1..c6c877051ba 100755 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -77,7 +77,8 @@ public interface NetworkManager extends NetworkService { * @throws InsufficientAddressCapacityException */ - PublicIp assignPublicIpAddress(long dcId, Long podId, Account owner, VlanType type, Long networkId, String requestedIp, boolean isSystem) throws InsufficientAddressCapacityException; + PublicIp assignPublicIpAddress(long dcId, Long podId, Account owner, VlanType type, Long networkId, String requestedIp, + boolean isSystem) throws InsufficientAddressCapacityException; /** @@ -89,7 +90,7 @@ public interface NetworkManager extends NetworkService { * @param ipAddress * @return true if it did; false if it didn't */ - public boolean releasePublicIpAddress(long id, long userId, Account caller); + public boolean disassociatePublicIpAddress(long id, long userId, Account caller); /** * Lists IP addresses that belong to VirtualNetwork VLANs @@ -369,7 +370,8 @@ public interface NetworkManager extends NetworkService { * @throws InsufficientCapacityException * @throws ResourceUnavailableException */ - NicProfile prepareNic(VirtualMachineProfile vmProfile, DeployDestination dest, ReservationContext context, long nicId, NetworkVO network) throws InsufficientVirtualNetworkCapcityException, + NicProfile prepareNic(VirtualMachineProfile vmProfile, DeployDestination dest, + ReservationContext context, long nicId, NetworkVO network) throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException, ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException; @@ -380,7 +382,8 @@ public interface NetworkManager extends NetworkService { * @throws ConcurrentOperationException * @throws ResourceUnavailableException */ - NicProfile releaseNic(VirtualMachineProfile vmProfile, NetworkVO network) throws ConcurrentOperationException, ResourceUnavailableException; + NicProfile releaseNic(VirtualMachineProfile vmProfile, NetworkVO network) + throws ConcurrentOperationException, ResourceUnavailableException; /** @@ -398,4 +401,18 @@ public interface NetworkManager extends NetworkService { */ List listPublicIpsAssignedToAccount(long accountId, long dcId, Boolean sourceNat); + + /** + * @param ipAddrId + * @param networkId + */ + IpAddress associateIPToGuestNetwork(long ipAddrId, long networkId) throws ResourceAllocationException, ResourceUnavailableException, + InsufficientAddressCapacityException, ConcurrentOperationException; + + + /** + * @param ipId + */ + void unassignIPFromVpcNetwork(long ipId); + } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index d7486f0e33d..13ba9721037 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -232,10 +232,6 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag @Inject UserVmDao _userVmDao = null; @Inject - ResourceLimitDao _limitDao = null; - @Inject - CapacityDao _capacityDao = null; - @Inject AlertManager _alertMgr; @Inject AccountManager _accountMgr; @@ -404,13 +400,15 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag if (addrs.size() == 0) { if (podId != null) { - InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", Pod.class, podId); + InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException + ("Insufficient address capacity", Pod.class, podId); // for now, we hardcode the table names, but we should ideally do a lookup for the tablename from the VO object. ex.addProxyObject("Pod", podId, "podId"); throw ex; } s_logger.warn(errorMessage.toString()); - InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", DataCenter.class, dcId); + InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException + ("Insufficient address capacity", DataCenter.class, dcId); ex.addProxyObject("data_center", dcId, "dcId"); throw ex; } @@ -432,9 +430,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag addr.setState(assign ? IpAddress.State.Allocated : IpAddress.State.Allocating); if (vlanUse != VlanType.DirectAttached || zone.getNetworkType() == NetworkType.Basic) { - Network guestNtwk = getNetwork(guestNetworkId); addr.setAssociatedWithNetworkId(guestNetworkId); - addr.setVpcId(guestNtwk.getVpcId()); addr.setVpcId(vpcId); } @@ -454,7 +450,8 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag @DB protected void markPublicIpAsAllocated(IPAddressVO addr) { - assert (addr.getState() == IpAddress.State.Allocating || addr.getState() == IpAddress.State.Free) : "Unable to transition from state " + addr.getState() + " to " + IpAddress.State.Allocated; + assert (addr.getState() == IpAddress.State.Allocating || addr.getState() == IpAddress.State.Free) : + "Unable to transition from state " + addr.getState() + " to " + IpAddress.State.Allocated; Transaction txn = Transaction.currentTxn(); @@ -470,7 +467,9 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag String guestType = vlan.getVlanType().toString(); - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NET_IP_ASSIGN, owner.getId(), addr.getDataCenterId(), addr.getId(), addr.getAddress().toString(), addr.isSourceNat(), guestType, addr.getSystem()); + UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NET_IP_ASSIGN, owner.getId(), + addr.getDataCenterId(), addr.getId(), addr.getAddress().toString(), addr.isSourceNat(), guestType, + addr.getSystem()); _usageEventDao.persist(usageEvent); // don't increment resource count for direct ip addresses if (addr.getAssociatedWithNetworkId() != null) { @@ -627,7 +626,8 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag List publicIps = new ArrayList(); if (userIps != null && !userIps.isEmpty()) { for (IPAddressVO userIp : userIps) { - PublicIp publicIp = new PublicIp(userIp, _vlanDao.findById(userIp.getVlanId()), NetUtils.createSequenceBasedMacAddress(userIp.getMacAddress())); + PublicIp publicIp = new PublicIp(userIp, _vlanDao.findById(userIp.getVlanId()), + NetUtils.createSequenceBasedMacAddress(userIp.getMacAddress())); publicIps.add(publicIp); } } @@ -636,17 +636,14 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag if (success) { for (IPAddressVO addr : userIps) { - if (addr.getState() == IpAddress.State.Allocating) { - - addr.setAssociatedWithNetworkId(network.getId()); markPublicIpAsAllocated(addr); - } else if (addr.getState() == IpAddress.State.Releasing) { // Cleanup all the resources for ip address if there are any, and only then un-assign ip in the // system if (cleanupIpResources(addr.getId(), Account.ACCOUNT_ID_SYSTEM, _accountMgr.getSystemAccount())) { - _ipAddressDao.unassignIpAddress(addr.getId()); + s_logger.debug("Unassiging ip address " + addr); + _ipAddressDao.unassignIpAddress(addr.getId()); } else { success = false; s_logger.warn("Failed to release resources for ip address id=" + addr.getId()); @@ -906,7 +903,8 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag return providerToIpList; } - protected boolean applyIpAssociations(Network network, boolean rulesRevoked, boolean continueOnError, List publicIps) throws ResourceUnavailableException { + protected boolean applyIpAssociations(Network network, boolean rulesRevoked, boolean continueOnError, + List publicIps) throws ResourceUnavailableException { boolean success = true; Map> ipToServices = getIpToServices(publicIps, rulesRevoked, false); @@ -1002,51 +1000,32 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } @Override - @DB @ActionEvent(eventType = EventTypes.EVENT_NET_IP_ASSIGN, eventDescription = "allocating Ip", create = true) - public IpAddress allocateIP(long networkId, Account ipOwner, boolean isSystem) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException { + public IpAddress allocateIP(Account ipOwner, boolean isSystem, long zoneId) + throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException { Account caller = UserContext.current().getCaller(); - long userId = UserContext.current().getCallerUserId(); - - long ownerId = ipOwner.getId(); - Network network = _networksDao.findById(networkId); - if (network == null) { - InvalidParameterValueException ex = new InvalidParameterValueException("Network id is invalid"); - ex.addProxyObject("networks", networkId, "networkId"); - throw ex; - } + long callerUserId = UserContext.current().getCallerUserId(); // check permissions _accountMgr.checkAccess(caller, null, false, ipOwner); - _accountMgr.checkAccess(ipOwner, AccessType.UseNetwork, false, network); - - DataCenter zone = _configMgr.getZone(network.getDataCenterId()); - - // allow associating IP addresses to guest network only - if (network.getTrafficType() != TrafficType.Guest) { - throw new InvalidParameterValueException("Ip address can be associated to the network with trafficType " + TrafficType.Guest); - } - - // In Advance zone only allow to do IP assoc for Isolated networks with source nat service enabled - if (zone.getNetworkType() == NetworkType.Advanced && - !(network.getGuestType() == GuestType.Isolated && areServicesSupportedInNetwork(network.getId(), Service.SourceNat))) { - throw new InvalidParameterValueException("In zone of type " + NetworkType.Advanced + - " ip address can be associated only to the network of guest type " + GuestType.Isolated + " with the " - + Service.SourceNat.getName() + " enabled"); - } - - // Check that network belongs to IP owner - skip this check for Basic zone as there is just one guest network, - // and it belongs to the system - if (zone.getNetworkType() != NetworkType.Basic && network.getAccountId() != ipOwner.getId()) { - throw new InvalidParameterValueException("The owner of the network is not the same as owner of the IP"); - } + + DataCenter zone = _configMgr.getZone(zoneId); + + return allocateIp(ipOwner, isSystem, caller, callerUserId, zone); + } + @DB + public IpAddress allocateIp(Account ipOwner, boolean isSystem, Account caller, long callerUserId, DataCenter zone) + throws ConcurrentOperationException, ResourceAllocationException, + InsufficientAddressCapacityException { + VlanType vlanType = VlanType.VirtualNetwork; boolean assign = false; if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getType())) { // zone is of type DataCenter. See DataCenterVO.java. - PermissionDeniedException ex = new PermissionDeniedException("Cannot perform this operation, Zone is currently disabled"); + PermissionDeniedException ex = new PermissionDeniedException("Cannot perform this operation, " + + "Zone is currently disabled"); ex.addProxyObject("data_center", zone.getId(), "zoneId"); throw ex; } @@ -1057,11 +1036,11 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag Account accountToLock = null; try { if (s_logger.isDebugEnabled()) { - s_logger.debug("Associate IP address called for user " + userId + " account " + ownerId); + s_logger.debug("Associate IP address called by the user " + callerUserId + " account " + ipOwner.getId()); } - accountToLock = _accountDao.acquireInLockTable(ownerId); + accountToLock = _accountDao.acquireInLockTable(ipOwner.getId()); if (accountToLock == null) { - s_logger.warn("Unable to lock account: " + ownerId); + s_logger.warn("Unable to lock account: " + ipOwner.getId()); throw new ConcurrentOperationException("Unable to acquire account lock"); } @@ -1073,42 +1052,29 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag // accountId will not be exceeded _resourceLimitMgr.checkResourceLimit(accountToLock, ResourceType.public_ip); - boolean isSourceNat = false; - txn.start(); - NetworkOffering offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); - boolean sharedSourceNat = offering.getSharedSourceNat(); - - if (!sharedSourceNat) { - if (getExistingSourceNat(ownerId, network.getId(), network.getVpcId()) == null) { - if (network.getGuestType() == GuestType.Isolated) { - isSourceNat = true; - } - } - } - - ip = fetchNewPublicIp(zone.getId(), null, null, ipOwner, vlanType, network.getId(), - isSourceNat, assign, null, isSystem, network.getVpcId()); + ip = fetchNewPublicIp(zone.getId(), null, null, ipOwner, vlanType, null, + false, assign, null, isSystem, null); if (ip == null) { - InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Unable to find available public IP addresses", DataCenter.class, zone.getId()); + InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException + ("Unable to find available public IP addresses", DataCenter.class, zone.getId()); ex.addProxyObject("data_center", zone.getId(), "zoneId"); throw ex; } UserContext.current().setEventDetails("Ip Id: " + ip.getId()); Ip ipAddress = ip.getAddress(); - s_logger.debug("Got " + ipAddress + " to assign for account " + ipOwner.getId() + " in zone " + network.getDataCenterId()); + s_logger.debug("Got " + ipAddress + " to assign for account " + ipOwner.getId() + " in zone " + zone.getId()); txn.commit(); } finally { if (accountToLock != null) { - _accountDao.releaseFromLockTable(ownerId); + _accountDao.releaseFromLockTable(ipOwner.getId()); s_logger.debug("Associate IP address lock released"); } } - return ip; } @@ -1140,10 +1106,10 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag return sourceNatIp; } - @Override @DB - @ActionEvent(eventType = EventTypes.EVENT_NET_IP_ASSIGN, eventDescription = "associating Ip", async = true) - public IpAddress associateIP(long ipId) throws ResourceAllocationException, ResourceUnavailableException, InsufficientAddressCapacityException, ConcurrentOperationException { + @Override + public IpAddress associateIPToGuestNetwork(long ipId, long networkId) throws ResourceAllocationException, ResourceUnavailableException, + InsufficientAddressCapacityException, ConcurrentOperationException { Account caller = UserContext.current().getCaller(); Account owner = null; @@ -1155,17 +1121,69 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag s_logger.debug("Unable to find ip address by id: " + ipId); return null; } + + if (ipToAssoc.getAssociatedWithNetworkId() != null) { + s_logger.debug("IP " + ipToAssoc + " is already assocaited with network id" + networkId); + return ipToAssoc; + } + + Network network = _networksDao.findById(networkId); + if (network != null) { + _accountMgr.checkAccess(caller, AccessType.UseNetwork, false, network); + } else { + s_logger.debug("Unable to find ip address by id: " + ipId); + return null; + } + + DataCenter zone = _configMgr.getZone(network.getDataCenterId()); - Network network = _networksDao.findById(ipToAssoc.getAssociatedWithNetworkId()); + // allow associating IP addresses to guest network only + if (network.getTrafficType() != TrafficType.Guest) { + throw new InvalidParameterValueException("Ip address can be associated to the network with trafficType " + + TrafficType.Guest); + } + // Check that network belongs to IP owner - skip this check for Basic zone as there is just one guest network, + // and it belongs to the system + if (zone.getNetworkType() != NetworkType.Basic && network.getAccountId() != owner.getId()) { + throw new InvalidParameterValueException("The owner of the network is not the same as owner of the IP"); + } + + // In Advance zone only allow to do IP assoc for Isolated networks with source nat service enabled + if (zone.getNetworkType() == NetworkType.Advanced && + !(network.getGuestType() == GuestType.Isolated && areServicesSupportedInNetwork(network.getId(), + Service.SourceNat))) { + throw new InvalidParameterValueException("In zone of type " + NetworkType.Advanced + + " ip address can be associated only to the network of guest type " + GuestType.Isolated + " with the " + + Service.SourceNat.getName() + " enabled"); + } + + NetworkOffering offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); + boolean sharedSourceNat = offering.getSharedSourceNat(); + boolean isSourceNat = false; + if (!sharedSourceNat) { + if (getExistingSourceNat(owner.getId(), networkId, null) == null) { + if (network.getGuestType() == GuestType.Isolated) { + isSourceNat = true; + } + } + } + + s_logger.debug("Associating ip " + ipToAssoc + " to network " + network); + IPAddressVO ip = _ipAddressDao.findById(ipId); + //update ip address with networkId + ip.setAssociatedWithNetworkId(networkId); + ip.setSourceNat(isSourceNat); + _ipAddressDao.update(ipId, ip); + boolean success = false; try { success = applyIpAssociations(network, false); if (success) { - s_logger.debug("Successfully associated ip address " + ip.getAddress().addr() + " for account " + owner.getId() + " in zone " + network.getDataCenterId()); + s_logger.debug("Successfully associated ip address " + ip.getAddress().addr() + " to network " + network); } else { - s_logger.warn("Failed to associate ip address " + ip.getAddress().addr() + " for account " + owner.getId() + " in zone " + network.getDataCenterId()); + s_logger.warn("Failed to associate ip address " + ip.getAddress().addr() + " to network " + network); } return ip; } catch (ResourceUnavailableException e) { @@ -1189,10 +1207,56 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } } } + + + @DB + protected IpAddress associateIPToVpc(long ipId, long vpcId) throws ResourceAllocationException, ResourceUnavailableException, + InsufficientAddressCapacityException, ConcurrentOperationException { + Account caller = UserContext.current().getCaller(); + Account owner = null; + + IpAddress ipToAssoc = getIp(ipId); + if (ipToAssoc != null) { + _accountMgr.checkAccess(caller, null, true, ipToAssoc); + owner = _accountMgr.getAccount(ipToAssoc.getAllocatedToAccountId()); + } else { + s_logger.debug("Unable to find ip address by id: " + ipId); + return null; + } + + Vpc vpc = _vpcMgr.getVpc(vpcId); + if (vpc == null) { + throw new InvalidParameterValueException("Invalid VPC id " + vpcId); + } + + // check permissions + _accountMgr.checkAccess(caller, null, true, owner, vpc); + + boolean isSourceNat = false; + if (getExistingSourceNat(owner.getId(), null, vpcId) == null) { + isSourceNat = true; + } + + s_logger.debug("Associating ip " + ipToAssoc + " to vpc " + vpc); + + Transaction txn = Transaction.currentTxn(); + txn.start(); + IPAddressVO ip = _ipAddressDao.findById(ipId); + //update ip address with networkId + ip.setVpcId(vpcId); + ip.setSourceNat(isSourceNat); + _ipAddressDao.update(ipId, ip); + txn.commit(); + + s_logger.debug("Successfully assigned ip " + ipToAssoc + " to vpc " + vpc); + + return _ipAddressDao.findById(ipId); + } + @Override @DB - public boolean releasePublicIpAddress(long addrId, long userId, Account caller) { + public boolean disassociatePublicIpAddress(long addrId, long userId, Account caller) { boolean success = true; // Cleanup all ip address resources - PF/LB/Static nat rules @@ -2199,7 +2263,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag @Override @DB @ActionEvent(eventType = EventTypes.EVENT_NET_IP_RELEASE, eventDescription = "disassociating Ip", async = true) - public boolean disassociateIpAddress(long ipAddressId) throws InsufficientAddressCapacityException { + public boolean releaseIpAddress(long ipAddressId) throws InsufficientAddressCapacityException { Long userId = UserContext.current().getCallerUserId(); Account caller = UserContext.current().getCaller(); @@ -2220,16 +2284,8 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag if (ipVO.getAllocatedToAccountId() != null) { _accountMgr.checkAccess(caller, null, true, ipVO); } - - //if ip address is a source nat ip in vpc, fail to disassociate - if (ipVO.getVpcId() != null && ipVO.isSourceNat()) { - throw new InvalidParameterValueException("IP address id=" + ipAddressId + " is a source nat for VPC id=" + - ipVO.getVpcId() + " and can't be released"); - } - Network associatedNetwork = getNetwork(ipVO.getAssociatedWithNetworkId()); - - if (ipVO.isSourceNat() && areServicesSupportedInNetwork(associatedNetwork.getId(), Service.SourceNat)) { + if (ipVO.isSourceNat()) { throw new IllegalArgumentException("ip address is used for source nat purposes and can not be disassociated."); } @@ -2241,7 +2297,8 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag // Check for account wide pool. It will have an entry for account_vlan_map. if (_accountVlanMapDao.findAccountVlanMap(ipVO.getAllocatedToAccountId(), ipVO.getVlanId()) != null) { //see IPaddressVO.java - InvalidParameterValueException ex = new InvalidParameterValueException("Sepcified IP address uuid belongs to Account wide IP pool and cannot be disassociated"); + InvalidParameterValueException ex = new InvalidParameterValueException("Sepcified IP address uuid belongs to" + + " Account wide IP pool and cannot be disassociated"); ex.addProxyObject("user_ip_address", ipAddressId, "ipAddressId"); throw ex; } @@ -2251,9 +2308,11 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag throw new InvalidParameterValueException("Can't release system IP address " + ipVO); } - boolean success = releasePublicIpAddress(ipAddressId, userId, caller); - if (success) { - Network guestNetwork = getNetwork(ipVO.getAssociatedWithNetworkId()); + boolean success = disassociatePublicIpAddress(ipAddressId, userId, caller); + + Long networkId = ipVO.getAssociatedWithNetworkId(); + if (success && networkId != null) { + Network guestNetwork = getNetwork(networkId); NetworkOffering offering = _configMgr.getNetworkOffering(guestNetwork.getNetworkOfferingId()); Long vmId = ipVO.getAssociatedWithVmId(); if (offering.getElasticIp() && vmId != null) { @@ -4255,7 +4314,9 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag String guestType = vlan.getVlanType().toString(); - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NET_IP_RELEASE, ip.getAllocatedToAccountId(), ip.getDataCenterId(), addrId, ip.getAddress().addr(), ip.isSourceNat(), guestType, ip.getSystem()); + UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NET_IP_RELEASE, + ip.getAllocatedToAccountId(), ip.getDataCenterId(), addrId, ip.getAddress().addr(), + ip.isSourceNat(), guestType, ip.getSystem()); _usageEventDao.persist(usageEvent); } @@ -4665,8 +4726,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } // static NAT rules can not programmed unless IP is associated with network service provider, so run IP -// association for - // the network so as to ensure IP is associated before applying rules (in add state) + // association for the network so as to ensure IP is associated before applying rules (in add state) applyIpAssociations(network, false, continueOnError, publicIps); // get provider @@ -5697,8 +5757,10 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag // release all ip addresses List ipsToRelease = _ipAddressDao.listByAssociatedNetwork(networkId, null); for (IPAddressVO ipToRelease : ipsToRelease) { - IPAddressVO ip = markIpAsUnavailable(ipToRelease.getId()); - assert (ip != null) : "Unable to mark the ip address id=" + ipToRelease.getId() + " as unavailable."; + if (ipToRelease.getVpcId() != null) { + IPAddressVO ip = markIpAsUnavailable(ipToRelease.getId()); + assert (ip != null) : "Unable to mark the ip address id=" + ipToRelease.getId() + " as unavailable."; + } } try { @@ -6354,7 +6416,8 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag protected PhysicalNetworkServiceProvider addDefaultSecurityGroupProviderToPhysicalNetwork(long physicalNetworkId) { - PhysicalNetworkServiceProvider nsp = addProviderToPhysicalNetwork(physicalNetworkId, Network.Provider.SecurityGroupProvider.getName(), null, null); + PhysicalNetworkServiceProvider nsp = addProviderToPhysicalNetwork(physicalNetworkId, + Network.Provider.SecurityGroupProvider.getName(), null, null); return nsp; } @@ -6628,7 +6691,8 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } } - public IpAddress assignSystemIp(long networkId, Account owner, boolean forElasticLb, boolean forElasticIp) throws InsufficientAddressCapacityException { + public IpAddress assignSystemIp(long networkId, Account owner, boolean forElasticLb, boolean forElasticIp) + throws InsufficientAddressCapacityException { Network guestNetwork = getNetwork(networkId); NetworkOffering off = _configMgr.getNetworkOffering(guestNetwork.getNetworkOfferingId()); IpAddress ip = null; @@ -6637,9 +6701,9 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag try { s_logger.debug("Allocating system IP address for load balancer rule..."); // allocate ip - ip = allocateIP(networkId, owner, true); + ip = allocateIP(owner, true, guestNetwork.getDataCenterId()); // apply ip associations - ip = associateIP(ip.getId()); + ip = associateIP(ip.getId(), networkId, null); } catch (ResourceAllocationException ex) { throw new CloudRuntimeException("Failed to allocate system ip due to ", ex); } catch (ConcurrentOperationException ex) { @@ -6663,7 +6727,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag if (networkId != null) { if (ip.getSystem()) { UserContext ctx = UserContext.current(); - if (!releasePublicIpAddress(ip.getId(), ctx.getCallerUserId(), ctx.getCaller())) { + if (!disassociatePublicIpAddress(ip.getId(), ctx.getCallerUserId(), ctx.getCaller())) { s_logger.warn("Unable to release system ip address id=" + ip.getId()); success = false; } else { @@ -6793,5 +6857,35 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } return false; } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_NET_IP_ASSIGN, eventDescription = "associating Ip", async = true) + public IpAddress associateIP(long ipId, Long networkId, Long vpcId) throws InsufficientAddressCapacityException, + ResourceAllocationException, ResourceUnavailableException, ConcurrentOperationException { + if (vpcId != null) { + return associateIPToVpc(ipId, vpcId); + } + + if (networkId != null) { + return associateIPToGuestNetwork(ipId, networkId); + } + + return null; + } + + @Override + public void unassignIPFromVpcNetwork(long ipId) { + IPAddressVO ip = _ipAddressDao.findById(ipId); + Long vpcId = ip.getVpcId(); + + if (vpcId == null) { + return; + } + + ip.setAssociatedWithNetworkId(null); + _ipAddressDao.update(ipId, ip); + s_logger.debug("IP address " + ip + " is no longer associated with the network inside vpc id=" + vpcId); + } + } diff --git a/server/src/com/cloud/network/firewall/FirewallManagerImpl.java b/server/src/com/cloud/network/firewall/FirewallManagerImpl.java index aef6d7ca77e..506b615bd9d 100644 --- a/server/src/com/cloud/network/firewall/FirewallManagerImpl.java +++ b/server/src/com/cloud/network/firewall/FirewallManagerImpl.java @@ -33,6 +33,7 @@ import com.cloud.event.EventTypes; import com.cloud.event.UsageEventVO; import com.cloud.event.dao.EventDao; import com.cloud.event.dao.UsageEventDao; +import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceUnavailableException; @@ -131,21 +132,38 @@ public class FirewallManagerImpl implements FirewallService, FirewallManager, Ma public FirewallRule createFirewallRule(FirewallRule rule) throws NetworkRuleConflictException { Account caller = UserContext.current().getCaller(); - return createFirewallRule(rule.getSourceIpAddressId(), caller, rule.getXid(), rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getProtocol(), rule.getSourceCidrList(), rule.getIcmpCode(), - rule.getIcmpType(), null, rule.getType()); + return createFirewallRule(rule.getSourceIpAddressId(), caller, rule.getXid(), rule.getSourcePortStart(), + rule.getSourcePortEnd(), rule.getProtocol(), rule.getSourceCidrList(), rule.getIcmpCode(), + rule.getIcmpType(), null, rule.getType(), rule.getNetworkId()); } @DB @Override @ActionEvent(eventType = EventTypes.EVENT_FIREWALL_OPEN, eventDescription = "creating firewall rule", create = true) - public FirewallRule createFirewallRule(long ipAddrId, Account caller, String xId, Integer portStart, Integer portEnd, String protocol, List sourceCidrList, Integer icmpCode, Integer icmpType, - Long relatedRuleId, FirewallRule.FirewallRuleType type) throws NetworkRuleConflictException { + public FirewallRule createFirewallRule(long ipAddrId, Account caller, String xId, Integer portStart, + Integer portEnd, String protocol, List sourceCidrList, Integer icmpCode, Integer icmpType, + Long relatedRuleId, FirewallRule.FirewallRuleType type, long networkId) throws NetworkRuleConflictException { + IPAddressVO ipAddress = _ipAddressDao.findById(ipAddrId); - // Validate ip address if (ipAddress == null && type == FirewallRule.FirewallRuleType.User) { - throw new InvalidParameterValueException("Unable to create port forwarding rule; ip id=" + ipAddrId + " doesn't exist in the system"); + throw new InvalidParameterValueException("Unable to create port forwarding rule; ip id=" + ipAddrId + + " doesn't exist in the system"); } + + //associate ip address to network (if needed) + if (ipAddress.getAssociatedWithNetworkId() == null) { + s_logger.debug("The ip is not associated with the network id="+ networkId + " so assigning"); + try { + _networkMgr.associateIPToGuestNetwork(ipAddrId, networkId); + } catch (Exception ex) { + s_logger.warn("Failed to associate ip id=" + ipAddrId + " to network id=" + networkId + " as " + + "a part of firewall rule creation"); + return null; + } + } + + _networkMgr.checkIpForService(ipAddress, Service.Firewall); validateFirewallRule(caller, ipAddress, portStart, portEnd, protocol, Purpose.Firewall, type); @@ -158,17 +176,14 @@ public class FirewallManagerImpl implements FirewallService, FirewallManager, Ma throw new InvalidParameterValueException("Can't specify start/end port when protocol is ICMP"); } - Long networkId = null; Long accountId = null; Long domainId = null; if (ipAddress != null) { - networkId = ipAddress.getAssociatedWithNetworkId(); accountId = ipAddress.getAllocatedToAccountId(); domainId = ipAddress.getAllocatedInDomainId(); } - _networkMgr.checkIpForService(ipAddress, Service.Firewall); Transaction txn = Transaction.currentTxn(); txn.start(); @@ -369,7 +384,8 @@ public class FirewallManagerImpl implements FirewallService, FirewallManager, Ma } @Override - public boolean applyRules(List rules, boolean continueOnError, boolean updateRulesInDB) throws ResourceUnavailableException { + public boolean applyRules(List rules, boolean continueOnError, boolean updateRulesInDB) + throws ResourceUnavailableException { boolean success = true; if (!_networkMgr.applyRules(rules, continueOnError)) { s_logger.warn("Rules are not completely applied"); @@ -380,10 +396,11 @@ public class FirewallManagerImpl implements FirewallService, FirewallManager, Ma if (rule.getState() == FirewallRule.State.Revoke) { FirewallRuleVO relatedRule = _firewallDao.findByRelatedId(rule.getId()); if (relatedRule != null) { - s_logger.warn("Can't remove the firewall rule id=" + rule.getId() + " as it has related firewall rule id=" + relatedRule.getId() + "; leaving it in Revoke state"); + s_logger.warn("Can't remove the firewall rule id=" + rule.getId() + + " as it has related firewall rule id=" + relatedRule.getId() + "; leaving it in Revoke state"); success = false; } else { - _firewallDao.remove(rule.getId()); + removeRule(rule); } } else if (rule.getState() == FirewallRule.State.Add) { FirewallRuleVO ruleVO = _firewallDao.findById(rule.getId()); @@ -397,6 +414,23 @@ public class FirewallManagerImpl implements FirewallService, FirewallManager, Ma return success; } + @DB + protected void removeRule(FirewallRule rule) { + //Lock ip address + IpAddress ip = _ipAddressDao.findById(rule.getSourceIpAddressId()); + + Transaction txn = Transaction.currentTxn(); + txn.start(); + //remove the rule + _firewallDao.remove(rule.getId()); + if (ip.getVpcId() != null && _firewallDao.listByIp(ip.getId()).isEmpty()) { + //if the rule is the last one for the ip address assigned to VPC, unassign it from the network + _networkMgr.unassignIPFromVpcNetwork(ip.getId()); + } + + txn.commit(); + } + @Override public boolean applyFirewallRules(long ipId, Account caller) throws ResourceUnavailableException { List rules = _firewallDao.listByIpAndPurpose(ipId, Purpose.Firewall); @@ -535,18 +569,21 @@ public class FirewallManagerImpl implements FirewallService, FirewallManager, Ma } @Override - public FirewallRule createRuleForAllCidrs(long ipAddrId, Account caller, Integer startPort, Integer endPort, String protocol, Integer icmpCode, Integer icmpType, Long relatedRuleId) + public FirewallRule createRuleForAllCidrs(long ipAddrId, Account caller, + Integer startPort, Integer endPort, String protocol, Integer icmpCode, Integer icmpType, Long relatedRuleId, long networkId) throws NetworkRuleConflictException { // If firwallRule for this port range already exists, return it - List rules = _firewallDao.listByIpPurposeAndProtocolAndNotRevoked(ipAddrId, startPort, endPort, protocol, Purpose.Firewall); + List rules = _firewallDao.listByIpPurposeAndProtocolAndNotRevoked(ipAddrId, startPort, endPort, + protocol, Purpose.Firewall); if (!rules.isEmpty()) { return rules.get(0); } List oneCidr = new ArrayList(); oneCidr.add(NetUtils.ALL_CIDRS); - return createFirewallRule(ipAddrId, caller, null, startPort, endPort, protocol, oneCidr, icmpCode, icmpType, relatedRuleId, FirewallRule.FirewallRuleType.User); + return createFirewallRule(ipAddrId, caller, null, startPort, endPort, protocol, oneCidr, icmpCode, icmpType, + relatedRuleId, FirewallRule.FirewallRuleType.User, networkId); } @Override @@ -654,7 +691,7 @@ public class FirewallManagerImpl implements FirewallService, FirewallManager, Ma for (FirewallRuleVO rule : systemRules) { try { this.createFirewallRule(ip.getId(), acct, rule.getXid(), rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getProtocol(), - rule.getSourceCidrList(), rule.getIcmpCode(), rule.getIcmpType(), rule.getRelated(), FirewallRuleType.System); + rule.getSourceCidrList(), rule.getIcmpCode(), rule.getIcmpType(), rule.getRelated(), FirewallRuleType.System, rule.getNetworkId()); } catch (Exception e) { s_logger.debug("Failed to add system wide firewall rule, due to:" + e.toString()); } diff --git a/server/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java b/server/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java index 8c15d807b44..d479f76e012 100644 --- a/server/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java +++ b/server/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java @@ -611,7 +611,7 @@ public class ElasticLoadBalancerManagerImpl implements IPAddressVO ipvo = _ipAddressDao.findById(ipId); ipvo.setAssociatedWithNetworkId(null); _ipAddressDao.update(ipvo.getId(), ipvo); - _networkMgr.releasePublicIpAddress(ipId, userId, caller); + _networkMgr.disassociatePublicIpAddress(ipId, userId, caller); _ipAddressDao.unassignIpAddress(ipId); } diff --git a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java index f3f72884fc1..e4ddfffda0b 100755 --- a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java +++ b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java @@ -702,7 +702,8 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa // Validate ip address if (ipAddressVo == null) { - throw new InvalidParameterValueException("Unable to create load balance rule; ip id=" + ipAddrId + " doesn't exist in the system"); + throw new InvalidParameterValueException("Unable to create load balance rule; ip id=" + ipAddrId + "" + + " doesn't exist in the system"); } else if (ipAddressVo.isOneToOneNat()) { throw new NetworkRuleConflictException("Can't do load balance on ip address: " + ipAddressVo.getAddress()); } @@ -719,7 +720,14 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa ip = _networkMgr.assignSystemIp(lb.getNetworkId(), lbOwner, true, false); lb.setSourceIpAddressId(ip.getId()); } + + + try { + if (ip.getAssociatedWithNetworkId() == null) { + s_logger.debug("The ip is not associated with the network id="+ lb.getNetworkId() + " so assigning"); + _networkMgr.associateIPToGuestNetwork(ipAddrId, lb.getNetworkId()); + } result = createLoadBalancer(lb, openFirewall); } catch (Exception ex) { s_logger.warn("Failed to create load balancer due to ", ex); @@ -755,10 +763,12 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa if (ipAddr == null || !ipAddr.readyToUse()) { throw new InvalidParameterValueException("Unable to create load balancer rule, invalid IP address id" + sourceIpId); } else if (ipAddr.isOneToOneNat()) { - throw new InvalidParameterValueException("Unable to create load balancer rule; ip id=" + sourceIpId + " has static nat enabled"); + throw new InvalidParameterValueException("Unable to create load balancer rule; ip id=" + sourceIpId + + " has static nat enabled"); } - _firewallMgr.validateFirewallRule(caller.getCaller(), ipAddr, srcPortStart, srcPortEnd, lb.getProtocol(), Purpose.LoadBalancing, FirewallRuleType.User); + _firewallMgr.validateFirewallRule(caller.getCaller(), ipAddr, srcPortStart, srcPortEnd, lb.getProtocol(), + Purpose.LoadBalancing, FirewallRuleType.User); networkId = ipAddr.getAssociatedWithNetworkId(); if (networkId == null) { @@ -784,7 +794,8 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa newRule = _lbDao.persist(newRule); if (openFirewall) { - _firewallMgr.createRuleForAllCidrs(sourceIpId, caller.getCaller(), lb.getSourcePortStart(), lb.getSourcePortEnd(), lb.getProtocol(), null, null, newRule.getId()); + _firewallMgr.createRuleForAllCidrs(sourceIpId, caller.getCaller(), lb.getSourcePortStart(), + lb.getSourcePortEnd(), lb.getProtocol(), null, null, newRule.getId(), networkId); } boolean success = true; @@ -931,7 +942,7 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa boolean success = true; if (ip.getSystem()) { s_logger.debug("Releasing system ip address " + lb.getSourceIpAddressId() + " as a part of delete lb rule"); - if (!_networkMgr.releasePublicIpAddress(lb.getSourceIpAddressId(), UserContext.current().getCallerUserId(), UserContext.current().getCaller())) { + if (!_networkMgr.disassociatePublicIpAddress(lb.getSourceIpAddressId(), UserContext.current().getCallerUserId(), UserContext.current().getCaller())) { s_logger.warn("Unable to release system ip address id=" + lb.getSourceIpAddressId() + " as a part of delete lb rule"); success = false; } else { diff --git a/server/src/com/cloud/network/rules/FirewallManager.java b/server/src/com/cloud/network/rules/FirewallManager.java index 2de4d062087..58e8750500b 100644 --- a/server/src/com/cloud/network/rules/FirewallManager.java +++ b/server/src/com/cloud/network/rules/FirewallManager.java @@ -67,10 +67,10 @@ public interface FirewallManager extends FirewallService { boolean revokeFirewallRule(long ruleId, boolean apply, Account caller, long userId); FirewallRule createFirewallRule(long ipAddrId, Account caller, String xId, Integer portStart, Integer portEnd, String protocol, List sourceCidrList, Integer icmpCode, Integer icmpType, Long relatedRuleId, - FirewallRule.FirewallRuleType type) + FirewallRule.FirewallRuleType type, long networkId) throws NetworkRuleConflictException; - FirewallRule createRuleForAllCidrs(long ipAddrId, Account caller, Integer startPort, Integer endPort, String protocol, Integer icmpCode, Integer icmpType, Long relatedRuleId) throws NetworkRuleConflictException; + FirewallRule createRuleForAllCidrs(long ipAddrId, Account caller, Integer startPort, Integer endPort, String protocol, Integer icmpCode, Integer icmpType, Long relatedRuleId, long networkId) throws NetworkRuleConflictException; boolean revokeAllFirewallRulesForNetwork(long networkId, long userId, Account caller) throws ResourceUnavailableException; diff --git a/server/src/com/cloud/network/rules/RulesManagerImpl.java b/server/src/com/cloud/network/rules/RulesManagerImpl.java index 05f1d3c4af5..d3207cb91fe 100755 --- a/server/src/com/cloud/network/rules/RulesManagerImpl.java +++ b/server/src/com/cloud/network/rules/RulesManagerImpl.java @@ -153,7 +153,8 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { @Override @DB @ActionEvent(eventType = EventTypes.EVENT_NET_RULE_ADD, eventDescription = "creating forwarding rule", create = true) - public PortForwardingRule createPortForwardingRule(PortForwardingRule rule, Long vmId, boolean openFirewall) throws NetworkRuleConflictException { + public PortForwardingRule createPortForwardingRule(PortForwardingRule rule, Long vmId, boolean openFirewall) + throws NetworkRuleConflictException { UserContext ctx = UserContext.current(); Account caller = ctx.getCaller(); @@ -167,10 +168,25 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { } else if (ipAddress.isOneToOneNat()) { throw new InvalidParameterValueException("Unable to create port forwarding rule; ip id=" + ipAddrId + " has static nat enabled"); } + + Long networkId = rule.getNetworkId(); + //associate ip address to network (if needed) + if (ipAddress.getAssociatedWithNetworkId() == null) { + s_logger.debug("The ip is not associated with the network id="+ networkId + " so assigning"); + try { + _networkMgr.associateIPToGuestNetwork(ipAddrId, networkId); + } catch (Exception ex) { + s_logger.warn("Failed to associate ip id=" + ipAddrId + " to network id=" + networkId + " as " + + "a part of port forwarding rule creation"); + return null; + } + } + + _networkMgr.checkIpForService(ipAddress, Service.PortForwarding); - _firewallMgr.validateFirewallRule(caller, ipAddress, rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getProtocol(), Purpose.PortForwarding, FirewallRuleType.User); - - Long networkId = ipAddress.getAssociatedWithNetworkId(); + _firewallMgr.validateFirewallRule(caller, ipAddress, rule.getSourcePortStart(), rule.getSourcePortEnd(), + rule.getProtocol(), Purpose.PortForwarding, FirewallRuleType.User); + Long accountId = ipAddress.getAllocatedToAccountId(); Long domainId = ipAddress.getAllocatedInDomainId(); @@ -187,12 +203,12 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { // 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 + ")."); + throw new InvalidParameterValueException("Unable to create port forwarding rule on address " + ipAddress + + ", invalid virtual machine id specified (" + vmId + ")."); } else { checkRuleAndUserVm(rule, vm, caller); } - _networkMgr.checkIpForService(ipAddress, Service.PortForwarding); // Verify that vm has nic in the network Ip dstIp = rule.getDestinationIpAddress(); @@ -206,13 +222,15 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { Transaction txn = Transaction.currentTxn(); txn.start(); - PortForwardingRuleVO newRule = new PortForwardingRuleVO(rule.getXid(), rule.getSourceIpAddressId(), rule.getSourcePortStart(), rule.getSourcePortEnd(), dstIp, rule.getDestinationPortStart(), + 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()); + _firewallMgr.createRuleForAllCidrs(ipAddrId, caller, rule.getSourcePortStart(), rule.getSourcePortEnd(), + rule.getProtocol(), null, null, newRule.getId(), networkId); } try { @@ -221,19 +239,17 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { 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); + 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(); } @@ -287,7 +303,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { // 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()); + _firewallMgr.createRuleForAllCidrs(ipAddrId, caller, rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getProtocol(), null, null, newRule.getId(), networkId); } try { @@ -321,30 +337,41 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { } @Override - public boolean enableStaticNat(long ipId, long vmId) throws NetworkRuleConflictException, ResourceUnavailableException { + public boolean enableStaticNat(long ipId, long vmId, long networkId) throws NetworkRuleConflictException, ResourceUnavailableException { UserContext ctx = UserContext.current(); Account caller = ctx.getCaller(); // Verify input parameters UserVmVO vm = _vmDao.findById(vmId); if (vm == null) { - throw new InvalidParameterValueException("Can't enable static nat for the address id=" + ipId + ", invalid virtual machine id specified (" + vmId + ")."); + throw new InvalidParameterValueException("Can't enable static nat for the address id=" + ipId + + ", invalid virtual machine id specified (" + vmId + ")."); } IPAddressVO ipAddress = _ipAddressDao.findById(ipId); if (ipAddress == null) { throw new InvalidParameterValueException("Unable to find ip address by id " + ipId); } + + boolean setNetworkId = false; + //associate ip address to network (if needed) + if (ipAddress.getAssociatedWithNetworkId() == null) { + s_logger.debug("The ip is not associated with the network id="+ networkId + " so assigning"); + try { + _networkMgr.associateIPToGuestNetwork(ipId, networkId); + } catch (Exception ex) { + s_logger.warn("Failed to associate ip id=" + ipId + " to network id=" + networkId + " as " + + "a part of enable static nat"); + return false; + } + setNetworkId = true; + } + + _networkMgr.checkIpForService(ipAddress, Service.StaticNat); // Check permissions checkIpAndUserVm(ipAddress, vm, caller); - // Verify that the ip is associated with the network and static nat service is supported for the network - Long networkId = ipAddress.getAssociatedWithNetworkId(); - if (networkId == null) { - throw new InvalidParameterValueException("Unable to enable static nat for the ipAddress id=" + ipId + " as ip is not associated with any network"); - } - // Check that vm has a nic in the network Nic guestNic = _networkMgr.getNicInNetwork(vmId, networkId); if (guestNic == null) { @@ -353,14 +380,12 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { Network network = _networkMgr.getNetwork(networkId); if (!_networkMgr.areServicesSupportedInNetwork(network.getId(), Service.StaticNat)) { - throw new InvalidParameterValueException("Unable to create static nat rule; StaticNat service is not supported in network id=" + networkId); + throw new InvalidParameterValueException("Unable to create static nat rule; StaticNat service is not " + + "supported in network id=" + networkId); } // Verify ip address parameter isIpReadyForStaticNat(vmId, ipAddress, caller, ctx.getCallerUserId()); - - _networkMgr.checkIpForService(ipAddress, Service.StaticNat); - ipAddress.setOneToOneNat(true); ipAddress.setAssociatedWithVmId(vmId); @@ -372,6 +397,9 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { } else { ipAddress.setOneToOneNat(false); ipAddress.setAssociatedWithVmId(null); + if (setNetworkId) { + ipAddress.setAssociatedWithNetworkId(null); + } _ipAddressDao.update(ipAddress.getId(), ipAddress); s_logger.warn("Failed to enable static nat rule for ip address " + ipId + " on the backend"); return false; @@ -382,7 +410,8 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { } } - protected void isIpReadyForStaticNat(long vmId, IPAddressVO ipAddress, Account caller, long callerUserId) throws NetworkRuleConflictException, ResourceUnavailableException { + protected void isIpReadyForStaticNat(long vmId, IPAddressVO ipAddress, Account caller, long callerUserId) + throws NetworkRuleConflictException, ResourceUnavailableException { if (ipAddress.isSourceNat()) { throw new InvalidParameterValueException("Can't enable static, ip address " + ipAddress + " is a sourceNat ip address"); } @@ -955,7 +984,8 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { @Override @DB - public FirewallRuleVO[] reservePorts(IpAddress ip, String protocol, FirewallRule.Purpose purpose, boolean openFirewall, Account caller, int... ports) throws NetworkRuleConflictException { + public FirewallRuleVO[] reservePorts(IpAddress ip, String protocol, FirewallRule.Purpose purpose, + boolean openFirewall, Account caller, int... ports) throws NetworkRuleConflictException { FirewallRuleVO[] rules = new FirewallRuleVO[ports.length]; Transaction txn = Transaction.currentTxn(); @@ -966,7 +996,8 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { rules[i] = _firewallDao.persist(rules[i]); if (openFirewall) { - _firewallMgr.createRuleForAllCidrs(ip.getId(), caller, ports[i], ports[i], protocol, null, null, rules[i].getId()); + _firewallMgr.createRuleForAllCidrs(ip.getId(), caller, ports[i], ports[i], protocol, null, null, + rules[i].getId(), ip.getAssociatedWithNetworkId()); } } txn.commit(); @@ -1033,8 +1064,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { } // if network has elastic IP functionality supported, we first have to disable static nat on old ip in order to -// re-enable it on the new one - // enable static nat takes care of that + // re-enable it on the new one enable static nat takes care of that Network guestNetwork = _networkMgr.getNetwork(ipAddress.getAssociatedWithNetworkId()); NetworkOffering offering = _configMgr.getNetworkOffering(guestNetwork.getNetworkOfferingId()); if (offering.getElasticIp()) { @@ -1075,14 +1105,17 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { } if (success) { + Transaction txn = Transaction.currentTxn(); + txn.start(); boolean isIpSystem = ipAddress.getSystem(); - ipAddress.setOneToOneNat(false); ipAddress.setAssociatedWithVmId(null); if (isIpSystem && !releaseIpIfElastic) { ipAddress.setSystem(false); } _ipAddressDao.update(ipAddress.getId(), ipAddress); + _networkMgr.unassignIPFromVpcNetwork(ipAddress.getId()); + txn.commit(); if (isIpSystem && releaseIpIfElastic && !_networkMgr.handleSystemIpRelease(ipAddress)) { s_logger.warn("Failed to release system ip address " + ipAddress); @@ -1161,7 +1194,8 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { dstIp = _networkMgr.getIpInNetwork(sourceIp.getAssociatedWithVmId(), networkId); } - StaticNatImpl staticNat = new StaticNatImpl(sourceIp.getAllocatedToAccountId(), sourceIp.getAllocatedInDomainId(), networkId, sourceIpId, dstIp, forRevoke); + StaticNatImpl staticNat = new StaticNatImpl(sourceIp.getAllocatedToAccountId(), sourceIp.getAllocatedInDomainId(), + networkId, sourceIpId, dstIp, forRevoke); staticNats.add(staticNat); try { @@ -1202,12 +1236,14 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { s_logger.debug("Allocated system ip " + ip + ", now enabling static nat on it for vm " + vm); try { - success = enableStaticNat(ip.getId(), vm.getId()); + success = enableStaticNat(ip.getId(), vm.getId(), guestNetwork.getId()); } catch (NetworkRuleConflictException ex) { - s_logger.warn("Failed to enable static nat as a part of enabling elasticIp and staticNat for vm " + vm + " in guest network " + guestNetwork + " due to exception ", ex); + s_logger.warn("Failed to enable static nat as a part of enabling elasticIp and staticNat for vm " + + vm + " in guest network " + guestNetwork + " due to exception ", ex); success = false; } catch (ResourceUnavailableException ex) { - s_logger.warn("Failed to enable static nat as a part of enabling elasticIp and staticNat for vm " + vm + " in guest network " + guestNetwork + " due to exception ", ex); + s_logger.warn("Failed to enable static nat as a part of enabling elasticIp and staticNat for vm " + + vm + " in guest network " + guestNetwork + " due to exception ", ex); success = false; } @@ -1221,5 +1257,4 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { } } } - } diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index 1d57e28be38..c2b85dc3488 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -859,7 +859,7 @@ public class VpcManagerImpl implements VpcManager, Manager{ List ipsToRelease = _ipAddressDao.listByAssociatedVpc(vpcId, null); s_logger.debug("Releasing ips for vpc id=" + vpcId + " as a part of vpc cleanup"); for (IPAddressVO ipToRelease : ipsToRelease) { - success = success && _ntwkMgr.releasePublicIpAddress(ipToRelease.getId(), callerUserId, caller); + success = success && _ntwkMgr.disassociatePublicIpAddress(ipToRelease.getId(), callerUserId, caller); if (!success) { s_logger.warn("Failed to cleanup ip " + ipToRelease + " as a part of vpc id=" + vpcId + " cleanup"); } diff --git a/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java b/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java index 035629ceb85..b1ee175b0e7 100755 --- a/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java +++ b/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java @@ -102,7 +102,8 @@ public class RemoteAccessVpnManagerImpl implements RemoteAccessVpnService, Manag SearchBuilder VpnSearch; @Override - public RemoteAccessVpn createRemoteAccessVpn(long publicIpId, String ipRange, boolean openFirewall) throws NetworkRuleConflictException { + public RemoteAccessVpn createRemoteAccessVpn(long publicIpId, String ipRange, boolean openFirewall, long networkId) + throws NetworkRuleConflictException { UserContext ctx = UserContext.current(); Account caller = ctx.getCaller(); @@ -114,11 +115,23 @@ public class RemoteAccessVpnManagerImpl implements RemoteAccessVpnService, Manag _accountMgr.checkAccess(caller, null, true, ipAddr); - if (!ipAddr.readyToUse() || ipAddr.getAssociatedWithNetworkId() == null) { + if (!ipAddr.readyToUse()) { throw new InvalidParameterValueException("The Ip address is not ready to be used yet: " + ipAddr.getAddress()); } IPAddressVO ipAddress = _ipAddressDao.findById(publicIpId); + + //associate ip address to network (if needed) + if (ipAddress.getAssociatedWithNetworkId() == null) { + s_logger.debug("The ip is not associated with the network id="+ networkId + " so assigning"); + try { + _networkMgr.associateIPToGuestNetwork(publicIpId, networkId); + } catch (Exception ex) { + s_logger.warn("Failed to associate ip id=" + publicIpId + " to network id=" + networkId + " as " + + "a part of remote access vpn creation"); + return null; + } + } _networkMgr.checkIpForService(ipAddress, Service.Vpn); RemoteAccessVpnVO vpnVO = _remoteAccessVpnDao.findByPublicIpAddress(publicIpId); @@ -132,7 +145,7 @@ public class RemoteAccessVpnManagerImpl implements RemoteAccessVpnService, Manag } // TODO: assumes one virtual network / domr per account per zone - vpnVO = _remoteAccessVpnDao.findByAccountAndNetwork(ipAddr.getAccountId(), ipAddr.getAssociatedWithNetworkId()); + vpnVO = _remoteAccessVpnDao.findByAccountAndNetwork(ipAddr.getAccountId(), networkId); if (vpnVO != null) { //if vpn is in Added state, return it to the api if (vpnVO.getState() == RemoteAccessVpn.State.Added) { @@ -142,7 +155,7 @@ public class RemoteAccessVpnManagerImpl implements RemoteAccessVpnService, Manag } //Verify that vpn service is enabled for the network - Network network = _networkMgr.getNetwork(ipAddr.getAssociatedWithNetworkId()); + Network network = _networkMgr.getNetwork(networkId); if (!_networkMgr.areServicesSupportedInNetwork(network.getId(), Service.Vpn)) { throw new InvalidParameterValueException("Vpn service is not supported in network id=" + ipAddr.getAssociatedWithNetworkId()); } diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index 3503d3f475d..8ce4ea7c31e 100755 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -597,7 +597,7 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag List ipsToRelease = _ipAddressDao.listByAccount(accountId); for (IpAddress ip : ipsToRelease) { s_logger.debug("Releasing ip " + ip + " as a part of account id=" + accountId + " cleanup"); - if (!_networkMgr.releasePublicIpAddress(ip.getId(), callerUserId, caller)) { + if (!_networkMgr.disassociatePublicIpAddress(ip.getId(), callerUserId, caller)) { s_logger.warn("Failed to release ip address " + ip + " as a part of account id=" + accountId + " clenaup"); accountCleanupNeeded = true; } diff --git a/server/test/com/cloud/network/MockNetworkManagerImpl.java b/server/test/com/cloud/network/MockNetworkManagerImpl.java index b0fccf0bbab..12583f885f9 100755 --- a/server/test/com/cloud/network/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/network/MockNetworkManagerImpl.java @@ -74,13 +74,13 @@ public class MockNetworkManagerImpl implements NetworkManager, Manager, NetworkS } @Override - public IpAddress associateIP(long ipId) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException, ResourceUnavailableException { + public IpAddress associateIPToGuestNetwork(long ipId, long networkId) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException, ResourceUnavailableException { // TODO Auto-generated method stub return null; } @Override - public boolean disassociateIpAddress(long ipAddressId) { + public boolean releaseIpAddress(long ipAddressId) { // TODO Auto-generated method stub return false; } @@ -181,7 +181,7 @@ public class MockNetworkManagerImpl implements NetworkManager, Manager, NetworkS @Override - public boolean releasePublicIpAddress(long id, long userId, Account caller) { + public boolean disassociatePublicIpAddress(long id, long userId, Account caller) { // TODO Auto-generated method stub return false; } @@ -764,8 +764,7 @@ public class MockNetworkManagerImpl implements NetworkManager, Manager, NetworkS } @Override - public IpAddress allocateIP(long networkId, Account ipOwner, - boolean isSystem) throws ResourceAllocationException, + public IpAddress allocateIP(Account ipOwner, boolean isSystem, long zoneId) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException { // TODO Auto-generated method stub return null; diff --git a/wscript b/wscript index edf3a13850c..5b3e8e74340 100644 --- a/wscript +++ b/wscript @@ -3,7 +3,7 @@ # the following two variables are used by the target "waf dist" # if you change 'em here, you need to change it also in cloud.spec, add a %changelog entry there, and add an entry in debian/changelog -VERSION = '3.0.3.2012-05-29T18:21:13Z' +VERSION = '3.0.3.2012-05-31T02:45:25Z' APPNAME = 'cloud' import shutil,os