cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ahu...@apache.org
Subject [13/16] Added missing files
Date Mon, 19 Aug 2013 21:12:21 GMT
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/45d23988/server/src/com/cloud/network/IpAddressManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/IpAddressManagerImpl.java b/server/src/com/cloud/network/IpAddressManagerImpl.java
new file mode 100644
index 0000000..b95d9c9
--- /dev/null
+++ b/server/src/com/cloud/network/IpAddressManagerImpl.java
@@ -0,0 +1,1918 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.network;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+import java.util.UUID;
+
+import javax.inject.Inject;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.acl.ControlledEntity.ACLType;
+import org.apache.cloudstack.acl.SecurityChecker.AccessType;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.cloudstack.region.PortableIp;
+import org.apache.cloudstack.region.PortableIpDao;
+import org.apache.cloudstack.region.PortableIpVO;
+import org.apache.cloudstack.region.Region;
+
+import com.cloud.agent.AgentManager;
+import com.cloud.alert.AlertManager;
+import com.cloud.api.ApiDBUtils;
+import com.cloud.configuration.Config;
+import com.cloud.configuration.ConfigurationManager;
+import com.cloud.configuration.Resource.ResourceType;
+import com.cloud.dc.AccountVlanMapVO;
+import com.cloud.dc.DataCenter;
+import com.cloud.dc.DataCenter.NetworkType;
+import com.cloud.dc.Pod;
+import com.cloud.dc.PodVlanMapVO;
+import com.cloud.dc.Vlan;
+import com.cloud.dc.Vlan.VlanType;
+import com.cloud.dc.VlanVO;
+import com.cloud.dc.dao.AccountVlanMapDao;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.dc.dao.DataCenterVnetDao;
+import com.cloud.dc.dao.PodVlanMapDao;
+import com.cloud.dc.dao.VlanDao;
+import com.cloud.deploy.DeployDestination;
+import com.cloud.domain.Domain;
+import com.cloud.domain.dao.DomainDao;
+import com.cloud.event.ActionEventUtils;
+import com.cloud.event.EventTypes;
+import com.cloud.event.UsageEventUtils;
+import com.cloud.event.dao.UsageEventDao;
+import com.cloud.exception.AccountLimitException;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientAddressCapacityException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.InsufficientVirtualNetworkCapcityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.PermissionDeniedException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.host.dao.HostDao;
+import com.cloud.network.IpAddress.State;
+import com.cloud.network.Network.Capability;
+import com.cloud.network.Network.GuestType;
+import com.cloud.network.Network.Provider;
+import com.cloud.network.Network.Service;
+import com.cloud.network.Networks.AddressFormat;
+import com.cloud.network.Networks.BroadcastDomainType;
+import com.cloud.network.Networks.IsolationType;
+import com.cloud.network.Networks.TrafficType;
+import com.cloud.network.addr.PublicIp;
+import com.cloud.network.dao.AccountGuestVlanMapDao;
+import com.cloud.network.dao.FirewallRulesDao;
+import com.cloud.network.dao.IPAddressDao;
+import com.cloud.network.dao.IPAddressVO;
+import com.cloud.network.dao.LoadBalancerDao;
+import com.cloud.network.dao.NetworkAccountDao;
+import com.cloud.network.dao.NetworkDao;
+import com.cloud.network.dao.NetworkDomainDao;
+import com.cloud.network.dao.NetworkServiceMapDao;
+import com.cloud.network.dao.NetworkVO;
+import com.cloud.network.dao.PhysicalNetworkDao;
+import com.cloud.network.dao.PhysicalNetworkServiceProviderDao;
+import com.cloud.network.dao.PhysicalNetworkTrafficTypeDao;
+import com.cloud.network.dao.UserIpv6AddressDao;
+import com.cloud.network.element.IpDeployer;
+import com.cloud.network.element.IpDeployingRequester;
+import com.cloud.network.element.NetworkElement;
+import com.cloud.network.element.StaticNatServiceProvider;
+import com.cloud.network.guru.NetworkGuru;
+import com.cloud.network.lb.LoadBalancingRulesManager;
+import com.cloud.network.rules.FirewallManager;
+import com.cloud.network.rules.FirewallRule;
+import com.cloud.network.rules.FirewallRule.Purpose;
+import com.cloud.network.rules.FirewallRuleVO;
+import com.cloud.network.rules.RulesManager;
+import com.cloud.network.rules.StaticNat;
+import com.cloud.network.rules.dao.PortForwardingRulesDao;
+import com.cloud.network.vpc.NetworkACLManager;
+import com.cloud.network.vpc.VpcManager;
+import com.cloud.network.vpc.dao.PrivateIpDao;
+import com.cloud.network.vpn.RemoteAccessVpnService;
+import com.cloud.offering.NetworkOffering;
+import com.cloud.offering.NetworkOffering.Availability;
+import com.cloud.offerings.NetworkOfferingVO;
+import com.cloud.offerings.dao.NetworkOfferingDao;
+import com.cloud.offerings.dao.NetworkOfferingDetailsDao;
+import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
+import com.cloud.org.Grouping;
+import com.cloud.server.ConfigurationServer;
+import com.cloud.user.Account;
+import com.cloud.user.AccountManager;
+import com.cloud.user.ResourceLimitService;
+import com.cloud.user.User;
+import com.cloud.user.UserVO;
+import com.cloud.user.dao.AccountDao;
+import com.cloud.user.dao.UserDao;
+import com.cloud.utils.Journal;
+import com.cloud.utils.Pair;
+import com.cloud.utils.db.DB;
+import com.cloud.utils.db.EntityManager;
+import com.cloud.utils.db.Filter;
+import com.cloud.utils.db.GlobalLock;
+import com.cloud.utils.db.JoinBuilder.JoinType;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.SearchCriteria.Op;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.net.Ip;
+import com.cloud.utils.net.NetUtils;
+import com.cloud.vm.Nic;
+import com.cloud.vm.NicProfile;
+import com.cloud.vm.ReservationContext;
+import com.cloud.vm.ReservationContextImpl;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachineProfile;
+import com.cloud.vm.dao.NicDao;
+import com.cloud.vm.dao.NicIpAliasDao;
+import com.cloud.vm.dao.NicSecondaryIpDao;
+import com.cloud.vm.dao.UserVmDao;
+import com.cloud.vm.dao.VMInstanceDao;
+
+public class IpAddressManagerImpl implements IpAddressManager {
+    private static final Logger s_logger = Logger.getLogger(IpAddressManagerImpl.class);
+
+    @Inject
+    NetworkManager _networkMgr = null;
+    @Inject
+    EntityManager _entityMgr = null;
+    @Inject
+    DataCenterDao _dcDao = null;
+    @Inject
+    VlanDao _vlanDao = null;
+    @Inject
+    IPAddressDao _ipAddressDao = null;
+    @Inject
+    AccountDao _accountDao = null;
+    @Inject
+    DomainDao _domainDao = null;
+    @Inject
+    UserDao _userDao = null;
+    @Inject
+    ConfigurationDao _configDao;
+    @Inject
+    UserVmDao _userVmDao = null;
+    @Inject
+    AlertManager _alertMgr;
+    @Inject
+    AccountManager _accountMgr;
+    @Inject
+    ConfigurationManager _configMgr;
+    @Inject
+    AccountVlanMapDao _accountVlanMapDao;
+    @Inject
+    NetworkOfferingDao _networkOfferingDao = null;
+    @Inject
+    NetworkDao _networksDao = null;
+    @Inject
+    NicDao _nicDao = null;
+    @Inject
+    RulesManager _rulesMgr;
+    @Inject
+    LoadBalancingRulesManager _lbMgr;
+    @Inject
+    RemoteAccessVpnService _vpnMgr;
+    @Inject
+    PodVlanMapDao _podVlanMapDao;
+    @Inject
+    NetworkOfferingDetailsDao _ntwkOffDetailsDao;
+    @Inject
+    ConfigurationServer _configServer;
+    @Inject
+    AccountGuestVlanMapDao _accountGuestVlanMapDao;
+    @Inject
+    DataCenterVnetDao _datacenterVnetDao;
+    @Inject
+    NetworkAccountDao _networkAccountDao;
+    @Inject
+    protected NicIpAliasDao _nicIpAliasDao;
+    @Inject
+    protected IPAddressDao _publicIpAddressDao;
+    @Inject
+    NetworkDomainDao _networkDomainDao;
+    @Inject
+    VMInstanceDao _vmDao;
+    @Inject
+    FirewallManager _firewallMgr;
+    @Inject
+    FirewallRulesDao _firewallDao;
+    @Inject
+    ResourceLimitService _resourceLimitMgr;
+
+    @Inject
+    NetworkOfferingServiceMapDao _ntwkOfferingSrvcDao;
+    @Inject
+    PhysicalNetworkDao _physicalNetworkDao;
+    @Inject
+    PhysicalNetworkServiceProviderDao _pNSPDao;
+    @Inject
+    PortForwardingRulesDao _portForwardingRulesDao;
+    @Inject
+    LoadBalancerDao _lbDao;
+    @Inject
+    PhysicalNetworkTrafficTypeDao _pNTrafficTypeDao;
+    @Inject
+    AgentManager _agentMgr;
+    @Inject
+    HostDao _hostDao;
+    @Inject
+    NetworkServiceMapDao _ntwkSrvcDao;
+    @Inject
+    StorageNetworkManager _stnwMgr;
+    @Inject
+    VpcManager _vpcMgr;
+    @Inject
+    PrivateIpDao _privateIpDao;
+    @Inject
+    NetworkACLManager _networkACLMgr;
+    @Inject
+    UsageEventDao _usageEventDao;
+    @Inject
+    NetworkModel _networkModel;
+    @Inject
+    NicSecondaryIpDao _nicSecondaryIpDao;
+    @Inject
+    UserIpv6AddressDao _ipv6Dao;
+    @Inject
+    Ipv6AddressManager _ipv6Mgr;
+    @Inject
+    PortableIpDao _portableIpDao;
+    SearchBuilder<IPAddressVO> AssignIpAddressSearch;
+    SearchBuilder<IPAddressVO> AssignIpAddressFromPodVlanSearch;
+
+    public boolean configure(String name, Map<String, Object> params) {
+        // populate providers
+        Map<Network.Service, Set<Network.Provider>> defaultSharedNetworkOfferingProviders = new HashMap<Network.Service, Set<Network.Provider>>();
+        Set<Network.Provider> defaultProviders = new HashSet<Network.Provider>();
+
+        defaultProviders.add(Network.Provider.VirtualRouter);
+        defaultSharedNetworkOfferingProviders.put(Service.Dhcp, defaultProviders);
+        defaultSharedNetworkOfferingProviders.put(Service.Dns, defaultProviders);
+        defaultSharedNetworkOfferingProviders.put(Service.UserData, defaultProviders);
+
+        Map<Network.Service, Set<Network.Provider>> defaultIsolatedNetworkOfferingProviders = defaultSharedNetworkOfferingProviders;
+        defaultIsolatedNetworkOfferingProviders.put(Service.Dhcp, defaultProviders);
+        defaultIsolatedNetworkOfferingProviders.put(Service.Dns, defaultProviders);
+        defaultIsolatedNetworkOfferingProviders.put(Service.UserData, defaultProviders);
+        defaultIsolatedNetworkOfferingProviders.put(Service.Firewall, defaultProviders);
+        defaultIsolatedNetworkOfferingProviders.put(Service.Gateway, defaultProviders);
+        defaultIsolatedNetworkOfferingProviders.put(Service.Lb, defaultProviders);
+        defaultIsolatedNetworkOfferingProviders.put(Service.StaticNat, defaultProviders);
+        defaultIsolatedNetworkOfferingProviders.put(Service.PortForwarding, defaultProviders);
+        defaultIsolatedNetworkOfferingProviders.put(Service.Vpn, defaultProviders);
+
+        Map<Network.Service, Set<Network.Provider>> defaultSharedSGEnabledNetworkOfferingProviders = new HashMap<Network.Service, Set<Network.Provider>>();
+        defaultSharedSGEnabledNetworkOfferingProviders.put(Service.Dhcp, defaultProviders);
+        defaultSharedSGEnabledNetworkOfferingProviders.put(Service.Dns, defaultProviders);
+        defaultSharedSGEnabledNetworkOfferingProviders.put(Service.UserData, defaultProviders);
+        Set<Provider> sgProviders = new HashSet<Provider>();
+        sgProviders.add(Provider.SecurityGroupProvider);
+        defaultSharedSGEnabledNetworkOfferingProviders.put(Service.SecurityGroup, sgProviders);
+
+        Map<Network.Service, Set<Network.Provider>> defaultIsolatedSourceNatEnabledNetworkOfferingProviders = new HashMap<Network.Service, Set<Network.Provider>>();
+        defaultProviders.clear();
+        defaultProviders.add(Network.Provider.VirtualRouter);
+        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Dhcp, defaultProviders);
+        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Dns, defaultProviders);
+        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.UserData, defaultProviders);
+        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Firewall, defaultProviders);
+        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Gateway, defaultProviders);
+        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Lb, defaultProviders);
+        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.SourceNat, defaultProviders);
+        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.StaticNat, defaultProviders);
+        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.PortForwarding, defaultProviders);
+        defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Vpn, defaultProviders);
+
+        Map<Network.Service, Set<Network.Provider>> defaultVPCOffProviders = new HashMap<Network.Service, Set<Network.Provider>>();
+        defaultProviders.clear();
+        defaultProviders.add(Network.Provider.VirtualRouter);
+        defaultVPCOffProviders.put(Service.Dhcp, defaultProviders);
+        defaultVPCOffProviders.put(Service.Dns, defaultProviders);
+        defaultVPCOffProviders.put(Service.UserData, defaultProviders);
+        defaultVPCOffProviders.put(Service.NetworkACL, defaultProviders);
+        defaultVPCOffProviders.put(Service.Gateway, defaultProviders);
+        defaultVPCOffProviders.put(Service.Lb, defaultProviders);
+        defaultVPCOffProviders.put(Service.SourceNat, defaultProviders);
+        defaultVPCOffProviders.put(Service.StaticNat, defaultProviders);
+        defaultVPCOffProviders.put(Service.PortForwarding, defaultProviders);
+        defaultVPCOffProviders.put(Service.Vpn, defaultProviders);
+
+
+
+        //#8 - network offering with internal lb service
+        Map<Network.Service, Set<Network.Provider>> internalLbOffProviders = new HashMap<Network.Service, Set<Network.Provider>>();
+        Set<Network.Provider> defaultVpcProvider = new HashSet<Network.Provider>();
+        defaultVpcProvider.add(Network.Provider.VPCVirtualRouter);
+
+        Set<Network.Provider> defaultInternalLbProvider = new HashSet<Network.Provider>();
+        defaultInternalLbProvider.add(Network.Provider.InternalLbVm);
+
+        internalLbOffProviders.put(Service.Dhcp, defaultVpcProvider);
+        internalLbOffProviders.put(Service.Dns, defaultVpcProvider);
+        internalLbOffProviders.put(Service.UserData, defaultVpcProvider);
+        internalLbOffProviders.put(Service.NetworkACL, defaultVpcProvider);
+        internalLbOffProviders.put(Service.Gateway, defaultVpcProvider);
+        internalLbOffProviders.put(Service.Lb, defaultInternalLbProvider);
+        internalLbOffProviders.put(Service.SourceNat, defaultVpcProvider);
+
+
+
+        Map<Network.Service, Set<Network.Provider>> netscalerServiceProviders = new HashMap<Network.Service, Set<Network.Provider>>();
+        Set<Network.Provider> vrProvider = new HashSet<Network.Provider>();
+        vrProvider.add(Provider.VirtualRouter);
+        Set<Network.Provider> sgProvider = new HashSet<Network.Provider>();
+        sgProvider.add(Provider.SecurityGroupProvider);
+        Set<Network.Provider> nsProvider = new HashSet<Network.Provider>();
+        nsProvider.add(Provider.Netscaler);
+        netscalerServiceProviders.put(Service.Dhcp, vrProvider);
+        netscalerServiceProviders.put(Service.Dns, vrProvider);
+        netscalerServiceProviders.put(Service.UserData, vrProvider);
+        netscalerServiceProviders.put(Service.SecurityGroup, sgProvider);
+        netscalerServiceProviders.put(Service.StaticNat, nsProvider);
+        netscalerServiceProviders.put(Service.Lb, nsProvider);
+
+        Map<Service, Map<Capability, String>> serviceCapabilityMap = new HashMap<Service, Map<Capability, String>>();
+        Map<Capability, String> elb = new HashMap<Capability, String>();
+        elb.put(Capability.ElasticLb, "true");
+        Map<Capability, String> eip = new HashMap<Capability, String>();
+        eip.put(Capability.ElasticIp, "true");
+        serviceCapabilityMap.put(Service.Lb, elb);
+        serviceCapabilityMap.put(Service.StaticNat, eip);
+
+
+        AssignIpAddressSearch = _ipAddressDao.createSearchBuilder();
+        AssignIpAddressSearch.and("dc", AssignIpAddressSearch.entity().getDataCenterId(), Op.EQ);
+        AssignIpAddressSearch.and("allocated", AssignIpAddressSearch.entity().getAllocatedTime(), Op.NULL);
+        AssignIpAddressSearch.and("vlanId", AssignIpAddressSearch.entity().getVlanId(), Op.IN);
+        SearchBuilder<VlanVO> vlanSearch = _vlanDao.createSearchBuilder();
+        vlanSearch.and("type", vlanSearch.entity().getVlanType(), Op.EQ);
+        vlanSearch.and("networkId", vlanSearch.entity().getNetworkId(), Op.EQ);
+        AssignIpAddressSearch.join("vlan", vlanSearch, vlanSearch.entity().getId(), AssignIpAddressSearch.entity().getVlanId(), JoinType.INNER);
+        AssignIpAddressSearch.done();
+
+        AssignIpAddressFromPodVlanSearch = _ipAddressDao.createSearchBuilder();
+        AssignIpAddressFromPodVlanSearch.and("dc", AssignIpAddressFromPodVlanSearch.entity().getDataCenterId(), Op.EQ);
+        AssignIpAddressFromPodVlanSearch.and("allocated", AssignIpAddressFromPodVlanSearch.entity().getAllocatedTime(), Op.NULL);
+        SearchBuilder<VlanVO> podVlanSearch = _vlanDao.createSearchBuilder();
+        podVlanSearch.and("type", podVlanSearch.entity().getVlanType(), Op.EQ);
+        podVlanSearch.and("networkId", podVlanSearch.entity().getNetworkId(), Op.EQ);
+        SearchBuilder<PodVlanMapVO> podVlanMapSB = _podVlanMapDao.createSearchBuilder();
+        podVlanMapSB.and("podId", podVlanMapSB.entity().getPodId(), Op.EQ);
+        AssignIpAddressFromPodVlanSearch.join("podVlanMapSB",
+            podVlanMapSB,
+            podVlanMapSB.entity().getVlanDbId(),
+            AssignIpAddressFromPodVlanSearch.entity().getVlanId(),
+            JoinType.INNER);
+        AssignIpAddressFromPodVlanSearch.join("vlan", podVlanSearch, podVlanSearch.entity().getId(), AssignIpAddressFromPodVlanSearch.entity().getVlanId(), JoinType.INNER);
+        AssignIpAddressFromPodVlanSearch.done();
+
+        Network.State.getStateMachine().registerListener(new NetworkStateListener(_usageEventDao, _networksDao));
+
+        s_logger.info("Network Manager is configured.");
+
+        return true;
+    }
+
+    private IpAddress allocateIP(Account ipOwner, boolean isSystem, long zoneId) throws ResourceAllocationException, InsufficientAddressCapacityException,
+        ConcurrentOperationException {
+        Account caller = CallContext.current().getCallingAccount();
+        long callerUserId = CallContext.current().getCallingUserId();
+        // check permissions
+        _accountMgr.checkAccess(caller, null, false, ipOwner);
+
+        DataCenter zone = _configMgr.getZone(zoneId);
+
+        return allocateIp(ipOwner, isSystem, caller, callerUserId, zone);
+    }
+
+    // An IP association is required in below cases
+    //  1.there is at least one public IP associated with the network on which first rule (PF/static NAT/LB) is being applied.
+    //  2.last rule (PF/static NAT/LB) on the public IP has been revoked. So the public IP should not be associated with any provider
+    boolean checkIfIpAssocRequired(Network network, boolean postApplyRules, List<PublicIp> publicIps) {
+        for (PublicIp ip : publicIps) {
+            if (ip.isSourceNat()) {
+                continue;
+            } else if (ip.isOneToOneNat()) {
+                continue;
+            } else {
+                Long totalCount = null;
+                Long revokeCount = null;
+                Long activeCount = null;
+                Long addCount = null;
+
+                totalCount = _firewallDao.countRulesByIpId(ip.getId());
+                if (postApplyRules) {
+                    revokeCount = _firewallDao.countRulesByIpIdAndState(ip.getId(), FirewallRule.State.Revoke);
+                } else {
+                    activeCount = _firewallDao.countRulesByIpIdAndState(ip.getId(), FirewallRule.State.Active);
+                    addCount = _firewallDao.countRulesByIpIdAndState(ip.getId(), FirewallRule.State.Add);
+                }
+
+                if (totalCount == null || totalCount.longValue() == 0L) {
+                    continue;
+                }
+
+                if (postApplyRules) {
+
+                    if (revokeCount != null && revokeCount.longValue() == totalCount.longValue()) {
+                        s_logger.trace("All rules are in Revoke state, have to dis-assiciate IP from the backend");
+                        return true;
+                    }
+                } else {
+                    if (activeCount != null && activeCount > 0) {
+                        continue;
+                    } else if (addCount != null && addCount.longValue() == totalCount.longValue()) {
+                        s_logger.trace("All rules are in Add state, have to assiciate IP with the backend");
+                        return true;
+                    } else {
+                        continue;
+                    }
+                }
+            }
+        }
+
+        // there are no IP's corresponding to this network that need to be associated with provider
+        return false;
+    }
+
+    @Override
+    public boolean applyRules(List<? extends FirewallRule> rules, FirewallRule.Purpose purpose, NetworkRuleApplier applier, boolean continueOnError)
+        throws ResourceUnavailableException {
+        if (rules == null || rules.size() == 0) {
+            s_logger.debug("There are no rules to forward to the network elements");
+            return true;
+        }
+
+        boolean success = true;
+        Network network = _networksDao.findById(rules.get(0).getNetworkId());
+        FirewallRuleVO.TrafficType trafficType = rules.get(0).getTrafficType();
+        List<PublicIp> publicIps = new ArrayList<PublicIp>();
+
+        if (!(rules.get(0).getPurpose() == FirewallRule.Purpose.Firewall && trafficType == FirewallRule.TrafficType.Egress)) {
+            // get the list of public ip's owned by the network
+            List<IPAddressVO> userIps = _ipAddressDao.listByAssociatedNetwork(network.getId(), null);
+            if (userIps != null && !userIps.isEmpty()) {
+                for (IPAddressVO userIp : userIps) {
+                    PublicIp publicIp = PublicIp.createFromAddrAndVlan(userIp, _vlanDao.findById(userIp.getVlanId()));
+                    publicIps.add(publicIp);
+                }
+            }
+        }
+        // rules can not programmed unless IP is associated with network service provider, so run IP assoication for
+        // the network so as to ensure IP is associated before applying rules (in add state)
+        if (checkIfIpAssocRequired(network, false, publicIps)) {
+            applyIpAssociations(network, false, continueOnError, publicIps);
+        }
+
+        try {
+            applier.applyRules(network, purpose, rules);
+        } catch (ResourceUnavailableException e) {
+            if (!continueOnError) {
+                throw e;
+            }
+            s_logger.warn("Problems with applying " + purpose + " rules but pushing on", e);
+            success = false;
+        }
+
+        // if there are no active rules associated with a public IP, then public IP need not be associated with a provider.
+        // This IPAssoc ensures, public IP is dis-associated after last active rule is revoked.
+        if (checkIfIpAssocRequired(network, true, publicIps)) {
+            applyIpAssociations(network, true, continueOnError, publicIps);
+        }
+
+        return success;
+    }
+
+    protected boolean cleanupIpResources(long ipId, long userId, Account caller) {
+        boolean success = true;
+
+        // Revoke all firewall rules for the ip
+        try {
+            s_logger.debug("Revoking all " + Purpose.Firewall + "rules as a part of public IP id=" + ipId + " release...");
+            if (!_firewallMgr.revokeFirewallRulesForIp(ipId, userId, caller)) {
+                s_logger.warn("Unable to revoke all the firewall rules for ip id=" + ipId + " as a part of ip release");
+                success = false;
+            }
+        } catch (ResourceUnavailableException e) {
+            s_logger.warn("Unable to revoke all firewall rules for ip id=" + ipId + " as a part of ip release", e);
+            success = false;
+        }
+
+        // Revoke all PF/Static nat rules for the ip
+        try {
+            s_logger.debug("Revoking all " + Purpose.PortForwarding + "/" + Purpose.StaticNat + " rules as a part of public IP id=" + ipId + " release...");
+            if (!_rulesMgr.revokeAllPFAndStaticNatRulesForIp(ipId, userId, caller)) {
+                s_logger.warn("Unable to revoke all the port forwarding rules for ip id=" + ipId + " as a part of ip release");
+                success = false;
+            }
+        } catch (ResourceUnavailableException e) {
+            s_logger.warn("Unable to revoke all the port forwarding rules for ip id=" + ipId + " as a part of ip release", e);
+            success = false;
+        }
+
+        s_logger.debug("Revoking all " + Purpose.LoadBalancing + " rules as a part of public IP id=" + ipId + " release...");
+        if (!_lbMgr.removeAllLoadBalanacersForIp(ipId, caller, userId)) {
+            s_logger.warn("Unable to revoke all the load balancer rules for ip id=" + ipId + " as a part of ip release");
+            success = false;
+        }
+
+        // remote access vpn can be enabled only for static nat ip, so this part should never be executed under normal
+        // conditions
+        // only when ip address failed to be cleaned up as a part of account destroy and was marked as Releasing, this part of
+        // the code would be triggered
+        s_logger.debug("Cleaning up remote access vpns as a part of public IP id=" + ipId + " release...");
+        try {
+            _vpnMgr.destroyRemoteAccessVpnForIp(ipId, caller);
+        } catch (ResourceUnavailableException e) {
+            s_logger.warn("Unable to destroy remote access vpn for ip id=" + ipId + " as a part of ip release", e);
+            success = false;
+        }
+
+        return success;
+    }
+
+    @Override
+    @DB
+    public boolean disassociatePublicIpAddress(long addrId, long userId, Account caller) {
+
+        boolean success = true;
+        // Cleanup all ip address resources - PF/LB/Static nat rules
+        if (!cleanupIpResources(addrId, userId, caller)) {
+            success = false;
+            s_logger.warn("Failed to release resources for ip address id=" + addrId);
+        }
+
+        IPAddressVO ip = markIpAsUnavailable(addrId);
+
+        assert (ip != null) : "Unable to mark the ip address id=" + addrId + " as unavailable.";
+        if (ip == null) {
+            return true;
+        }
+
+        if (s_logger.isDebugEnabled()) {
+            s_logger.debug("Releasing ip id=" + addrId + "; sourceNat = " + ip.isSourceNat());
+        }
+
+        if (ip.getAssociatedWithNetworkId() != null) {
+            Network network = _networksDao.findById(ip.getAssociatedWithNetworkId());
+            try {
+                if (!applyIpAssociations(network, true)) {
+                    s_logger.warn("Unable to apply ip address associations for " + network);
+                    success = false;
+                }
+            } catch (ResourceUnavailableException e) {
+                throw new CloudRuntimeException("We should never get to here because we used true when applyIpAssociations", e);
+            }
+        } else {
+            if (ip.getState() == IpAddress.State.Releasing) {
+                _ipAddressDao.unassignIpAddress(ip.getId());
+            }
+        }
+
+        if (success) {
+            if (ip.isPortable()) {
+                releasePortableIpAddress(addrId);
+            }
+            s_logger.debug("Released a public ip id=" + addrId);
+        }
+
+        return success;
+    }
+
+    @DB
+    @Override
+    public boolean releasePortableIpAddress(long addrId) {
+        Transaction txn = Transaction.currentTxn();
+        GlobalLock portableIpLock = GlobalLock.getInternLock("PortablePublicIpRange");
+
+        txn.start();
+        try {
+            portableIpLock.lock(5);
+            IPAddressVO ip = _ipAddressDao.findById(addrId);
+
+            // unassign portable IP
+            PortableIpVO portableIp = _portableIpDao.findByIpAddress(ip.getAddress().addr());
+            _portableIpDao.unassignIpAddress(portableIp.getId());
+
+            // removed the provisioned vlan
+            VlanVO vlan = _vlanDao.findById(ip.getVlanId());
+            _vlanDao.remove(vlan.getId());
+
+            // remove the provisioned public ip address
+            _ipAddressDao.remove(ip.getId());
+
+            txn.commit();
+            return true;
+        } finally {
+            portableIpLock.releaseRef();
+        }
+    }
+
+    @Override
+    public PublicIp assignPublicIpAddress(long dcId, Long podId, Account owner, VlanType type, Long networkId, String requestedIp, boolean isSystem)
+        throws InsufficientAddressCapacityException {
+        return fetchNewPublicIp(dcId, podId, null, owner, type, networkId, false, true, requestedIp, isSystem, null);
+    }
+
+    @Override
+    public PublicIp assignPublicIpAddressFromVlans(long dcId, Long podId, Account owner, VlanType type, List<Long> vlanDbIds, Long networkId, String requestedIp, boolean isSystem)
+        throws InsufficientAddressCapacityException {
+        return fetchNewPublicIp(dcId, podId, vlanDbIds, owner, type, networkId, false, true, requestedIp, isSystem, null);
+    }
+
+    @DB
+    public PublicIp fetchNewPublicIp(long dcId, Long podId, List<Long> vlanDbIds, Account owner, VlanType vlanUse, Long guestNetworkId, boolean sourceNat, boolean assign,
+        String requestedIp, boolean isSystem, Long vpcId) throws InsufficientAddressCapacityException {
+        StringBuilder errorMessage = new StringBuilder("Unable to get ip adress in ");
+        boolean fetchFromDedicatedRange = false;
+        List<Long> dedicatedVlanDbIds = new ArrayList<Long>();
+        List<Long> nonDedicatedVlanDbIds = new ArrayList<Long>();
+
+        Transaction txn = Transaction.currentTxn();
+        txn.start();
+        SearchCriteria<IPAddressVO> sc = null;
+        if (podId != null) {
+            sc = AssignIpAddressFromPodVlanSearch.create();
+            sc.setJoinParameters("podVlanMapSB", "podId", podId);
+            errorMessage.append(" pod id=" + podId);
+        } else {
+            sc = AssignIpAddressSearch.create();
+            errorMessage.append(" zone id=" + dcId);
+        }
+
+        // If owner has dedicated Public IP ranges, fetch IP from the dedicated range
+        // Otherwise fetch IP from the system pool
+        List<AccountVlanMapVO> maps = _accountVlanMapDao.listAccountVlanMapsByAccount(owner.getId());
+        for (AccountVlanMapVO map : maps) {
+            if (vlanDbIds == null || vlanDbIds.contains(map.getVlanDbId()))
+                dedicatedVlanDbIds.add(map.getVlanDbId());
+        }
+        List<VlanVO> nonDedicatedVlans = _vlanDao.listZoneWideNonDedicatedVlans(dcId);
+        for (VlanVO nonDedicatedVlan : nonDedicatedVlans) {
+            if (vlanDbIds == null || vlanDbIds.contains(nonDedicatedVlan.getId()))
+                nonDedicatedVlanDbIds.add(nonDedicatedVlan.getId());
+        }
+        if (dedicatedVlanDbIds != null && !dedicatedVlanDbIds.isEmpty()) {
+            fetchFromDedicatedRange = true;
+            sc.setParameters("vlanId", dedicatedVlanDbIds.toArray());
+            errorMessage.append(", vlanId id=" + dedicatedVlanDbIds.toArray());
+        } else if (nonDedicatedVlanDbIds != null && !nonDedicatedVlanDbIds.isEmpty()) {
+            sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray());
+            errorMessage.append(", vlanId id=" + nonDedicatedVlanDbIds.toArray());
+        } else {
+            if (podId != null) {
+                InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", Pod.class, podId);
+                ex.addProxyObject(ApiDBUtils.findPodById(podId).getUuid());
+                throw ex;
+            }
+            s_logger.warn(errorMessage.toString());
+            InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", DataCenter.class, dcId);
+            ex.addProxyObject(ApiDBUtils.findZoneById(dcId).getUuid());
+            throw ex;
+        }
+
+        sc.setParameters("dc", dcId);
+
+        DataCenter zone = _configMgr.getZone(dcId);
+
+        // for direct network take ip addresses only from the vlans belonging to the network
+        if (vlanUse == VlanType.DirectAttached) {
+            sc.setJoinParameters("vlan", "networkId", guestNetworkId);
+            errorMessage.append(", network id=" + guestNetworkId);
+        }
+        sc.setJoinParameters("vlan", "type", vlanUse);
+
+        if (requestedIp != null) {
+            sc.addAnd("address", SearchCriteria.Op.EQ, requestedIp);
+            errorMessage.append(": requested ip " + requestedIp + " is not available");
+        }
+
+        Filter filter = new Filter(IPAddressVO.class, "vlanId", true, 0l, 1l);
+
+        List<IPAddressVO> addrs = _ipAddressDao.lockRows(sc, filter, true);
+
+        // If all the dedicated IPs of the owner are in use fetch an IP from the system pool
+        if (addrs.size() == 0 && fetchFromDedicatedRange) {
+            // Verify if account is allowed to acquire IPs from the system
+            boolean useSystemIps = Boolean.parseBoolean(_configServer.getConfigValue(Config.UseSystemPublicIps.key(),
+                Config.ConfigurationParameterScope.account.toString(),
+                owner.getId()));
+            if (useSystemIps && nonDedicatedVlanDbIds != null && !nonDedicatedVlanDbIds.isEmpty()) {
+                fetchFromDedicatedRange = false;
+                sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray());
+                errorMessage.append(", vlanId id=" + nonDedicatedVlanDbIds.toArray());
+                addrs = _ipAddressDao.lockRows(sc, filter, true);
+            }
+        }
+
+        if (addrs.size() == 0) {
+            if (podId != null) {
+                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(ApiDBUtils.findPodById(podId).getUuid());
+                throw ex;
+            }
+            s_logger.warn(errorMessage.toString());
+            InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", DataCenter.class, dcId);
+            ex.addProxyObject(ApiDBUtils.findZoneById(dcId).getUuid());
+            throw ex;
+        }
+
+        assert (addrs.size() == 1) : "Return size is incorrect: " + addrs.size();
+
+        if (!fetchFromDedicatedRange) {
+            // Check that the maximum number of public IPs for the given accountId will not be exceeded
+            try {
+                _resourceLimitMgr.checkResourceLimit(owner, ResourceType.public_ip);
+            } catch (ResourceAllocationException ex) {
+                s_logger.warn("Failed to allocate resource of type " + ex.getResourceType() + " for account " + owner);
+                throw new AccountLimitException("Maximum number of public IP addresses for account: " + owner.getAccountName() + " has been exceeded.");
+            }
+        }
+
+        IPAddressVO addr = addrs.get(0);
+        addr.setSourceNat(sourceNat);
+        addr.setAllocatedTime(new Date());
+        addr.setAllocatedInDomainId(owner.getDomainId());
+        addr.setAllocatedToAccountId(owner.getId());
+        addr.setSystem(isSystem);
+
+        if (assign) {
+            markPublicIpAsAllocated(addr);
+        } else {
+            addr.setState(IpAddress.State.Allocating);
+        }
+        addr.setState(assign ? IpAddress.State.Allocated : IpAddress.State.Allocating);
+
+        if (vlanUse != VlanType.DirectAttached || zone.getNetworkType() == NetworkType.Basic) {
+            addr.setAssociatedWithNetworkId(guestNetworkId);
+            addr.setVpcId(vpcId);
+        }
+
+        _ipAddressDao.update(addr.getId(), addr);
+
+        txn.commit();
+
+        if (vlanUse == VlanType.VirtualNetwork) {
+            _firewallMgr.addSystemFirewallRules(addr, owner);
+        }
+
+        return PublicIp.createFromAddrAndVlan(addr, _vlanDao.findById(addr.getVlanId()));
+    }
+
+    @DB
+    @Override
+    public 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;
+
+        Transaction txn = Transaction.currentTxn();
+
+        Account owner = _accountMgr.getAccount(addr.getAllocatedToAccountId());
+
+        txn.start();
+        addr.setState(IpAddress.State.Allocated);
+        _ipAddressDao.update(addr.getId(), addr);
+
+        // Save usage event
+        if (owner.getAccountId() != Account.ACCOUNT_ID_SYSTEM) {
+            VlanVO vlan = _vlanDao.findById(addr.getVlanId());
+
+            String guestType = vlan.getVlanType().toString();
+
+            if (!isIpDedicated(addr)) {
+                UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_ASSIGN,
+                    owner.getId(),
+                    addr.getDataCenterId(),
+                    addr.getId(),
+                    addr.getAddress().toString(),
+                    addr.isSourceNat(),
+                    guestType,
+                    addr.getSystem(),
+                    addr.getClass().getName(),
+                    addr.getUuid());
+            }
+            // don't increment resource count for direct and dedicated ip addresses
+            if (addr.getAssociatedWithNetworkId() != null && !isIpDedicated(addr)) {
+                _resourceLimitMgr.incrementResourceCount(owner.getId(), ResourceType.public_ip);
+            }
+        }
+
+        txn.commit();
+    }
+
+    private boolean isIpDedicated(IPAddressVO addr) {
+        List<AccountVlanMapVO> maps = _accountVlanMapDao.listAccountVlanMapsByVlan(addr.getVlanId());
+        if (maps != null && !maps.isEmpty())
+            return true;
+        return false;
+    }
+
+    @Override
+    public PublicIp assignSourceNatIpAddressToGuestNetwork(Account owner, Network guestNetwork) throws InsufficientAddressCapacityException, ConcurrentOperationException {
+        assert (guestNetwork.getTrafficType() != null) : "You're asking for a source nat but your network "
+                                                         + "can't participate in source nat.  What do you have to say for yourself?";
+        long dcId = guestNetwork.getDataCenterId();
+
+        IPAddressVO sourceNatIp = getExistingSourceNatInNetwork(owner.getId(), guestNetwork.getId());
+
+        PublicIp ipToReturn = null;
+        if (sourceNatIp != null) {
+            ipToReturn = PublicIp.createFromAddrAndVlan(sourceNatIp, _vlanDao.findById(sourceNatIp.getVlanId()));
+        } else {
+            ipToReturn = assignDedicateIpAddress(owner, guestNetwork.getId(), null, dcId, true);
+        }
+
+        return ipToReturn;
+    }
+
+    @DB
+    @Override
+    public PublicIp assignDedicateIpAddress(Account owner, Long guestNtwkId, Long vpcId, long dcId, boolean isSourceNat) throws ConcurrentOperationException,
+        InsufficientAddressCapacityException {
+
+        long ownerId = owner.getId();
+
+        PublicIp ip = null;
+        Transaction txn = Transaction.currentTxn();
+        try {
+            txn.start();
+
+            owner = _accountDao.acquireInLockTable(ownerId);
+
+            if (owner == null) {
+                // this ownerId comes from owner or type Account. See the class "AccountVO" and the annotations in that class
+                // to get the table name and field name that is queried to fill this ownerid.
+                ConcurrentOperationException ex = new ConcurrentOperationException("Unable to lock account");
+                throw ex;
+            }
+            if (s_logger.isDebugEnabled()) {
+                s_logger.debug("lock account " + ownerId + " is acquired");
+            }
+
+            ip = fetchNewPublicIp(dcId, null, null, owner, VlanType.VirtualNetwork, guestNtwkId, isSourceNat, false, null, false, vpcId);
+            IPAddressVO publicIp = ip.ip();
+
+            markPublicIpAsAllocated(publicIp);
+            _ipAddressDao.update(publicIp.getId(), publicIp);
+
+            txn.commit();
+            return ip;
+        } finally {
+            if (owner != null) {
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug("Releasing lock account " + ownerId);
+                }
+
+                _accountDao.releaseFromLockTable(ownerId);
+            }
+            if (ip == null) {
+                txn.rollback();
+                s_logger.error("Unable to get source nat ip address for account " + ownerId);
+            }
+        }
+    }
+
+    @Override
+    public boolean applyIpAssociations(Network network, boolean continueOnError) throws ResourceUnavailableException {
+        List<IPAddressVO> userIps = _ipAddressDao.listByAssociatedNetwork(network.getId(), null);
+        boolean success = true;
+
+        // CloudStack will take a lazy approach to associate an acquired public IP to a network service provider as
+        // it will not know what service an acquired IP will be used for. An IP is actually associated with a provider when first
+        // rule is applied. Similarly when last rule on the acquired IP is revoked, IP is not associated with any provider
+        // but still be associated with the account. At this point just mark IP as allocated or released.
+        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());
+                } else {
+                    success = false;
+                    s_logger.warn("Failed to release resources for ip address id=" + addr.getId());
+                }
+            }
+        }
+
+        return success;
+    }
+
+    // CloudStack will take a lazy approach to associate an acquired public IP to a network service provider as
+    // it will not know what a acquired IP will be used for. An IP is actually associated with a provider when first
+    // rule is applied. Similarly when last rule on the acquired IP is revoked, IP is not associated with any provider
+    // but still be associated with the account. Its up to caller of this function to decide when to invoke IPAssociation
+    @Override
+    public boolean applyIpAssociations(Network network, boolean postApplyRules, boolean continueOnError, List<? extends PublicIpAddress> publicIps)
+        throws ResourceUnavailableException {
+        boolean success = true;
+
+        Map<PublicIpAddress, Set<Service>> ipToServices = _networkModel.getIpToServices(publicIps, postApplyRules, true);
+        Map<Provider, ArrayList<PublicIpAddress>> providerToIpList = _networkModel.getProviderToIpList(network, ipToServices);
+
+        for (Provider provider : providerToIpList.keySet()) {
+            try {
+                ArrayList<PublicIpAddress> ips = providerToIpList.get(provider);
+                if (ips == null || ips.isEmpty()) {
+                    continue;
+                }
+                IpDeployer deployer = null;
+                NetworkElement element = _networkModel.getElementImplementingProvider(provider.getName());
+                if (!(element instanceof IpDeployingRequester)) {
+                    throw new CloudRuntimeException("Element " + element + " is not a IpDeployingRequester!");
+                }
+                deployer = ((IpDeployingRequester)element).getIpDeployer(network);
+                if (deployer == null) {
+                    throw new CloudRuntimeException("Fail to get ip deployer for element: " + element);
+                }
+                Set<Service> services = new HashSet<Service>();
+                for (PublicIpAddress ip : ips) {
+                    if (!ipToServices.containsKey(ip)) {
+                        continue;
+                    }
+                    services.addAll(ipToServices.get(ip));
+                }
+                deployer.applyIps(network, ips, services);
+            } catch (ResourceUnavailableException e) {
+                success = false;
+                if (!continueOnError) {
+                    throw e;
+                } else {
+                    s_logger.debug("Resource is not available: " + provider.getName(), e);
+                }
+            }
+        }
+
+        return success;
+    }
+
+    @DB
+    @Override
+    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");
+            ex.addProxyObject(zone.getUuid(), "zoneId");
+            throw ex;
+        }
+
+        PublicIp ip = null;
+
+        Transaction txn = Transaction.currentTxn();
+        Account accountToLock = null;
+        try {
+            if (s_logger.isDebugEnabled()) {
+                s_logger.debug("Associate IP address called by the user " + callerUserId + " account " + ipOwner.getId());
+            }
+            accountToLock = _accountDao.acquireInLockTable(ipOwner.getId());
+            if (accountToLock == null) {
+                s_logger.warn("Unable to lock account: " + ipOwner.getId());
+                throw new ConcurrentOperationException("Unable to acquire account lock");
+            }
+
+            if (s_logger.isDebugEnabled()) {
+                s_logger.debug("Associate IP address lock acquired");
+            }
+
+            txn.start();
+
+            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());
+                ex.addProxyObject(ApiDBUtils.findZoneById(zone.getId()).getUuid());
+                throw ex;
+            }
+            CallContext.current().setEventDetails("Ip Id: " + ip.getId());
+            Ip ipAddress = ip.getAddress();
+
+            s_logger.debug("Got " + ipAddress + " to assign for account " + ipOwner.getId() + " in zone " + zone.getId());
+
+            txn.commit();
+        } finally {
+            if (accountToLock != null) {
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug("Releasing lock account " + ipOwner);
+                }
+                _accountDao.releaseFromLockTable(ipOwner.getId());
+                s_logger.debug("Associate IP address lock released");
+            }
+        }
+        return ip;
+    }
+
+    @Override
+    @DB
+    public IpAddress allocatePortableIp(Account ipOwner, Account caller, long dcId, Long networkId, Long vpcID) throws ConcurrentOperationException, ResourceAllocationException,
+        InsufficientAddressCapacityException {
+
+        Transaction txn = Transaction.currentTxn();
+        GlobalLock portableIpLock = GlobalLock.getInternLock("PortablePublicIpRange");
+        PortableIpVO allocatedPortableIp;
+        IPAddressVO ipaddr;
+
+        try {
+            portableIpLock.lock(5);
+
+            txn.start();
+
+            List<PortableIpVO> portableIpVOs = _portableIpDao.listByRegionIdAndState(1, PortableIp.State.Free);
+            if (portableIpVOs == null || portableIpVOs.isEmpty()) {
+                InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Unable to find available portable IP addresses", Region.class, new Long(1));
+                throw ex;
+            }
+
+            // allocate first portable IP to the user
+            allocatedPortableIp = portableIpVOs.get(0);
+            allocatedPortableIp.setAllocatedTime(new Date());
+            allocatedPortableIp.setAllocatedToAccountId(ipOwner.getAccountId());
+            allocatedPortableIp.setAllocatedInDomainId(ipOwner.getDomainId());
+            allocatedPortableIp.setState(PortableIp.State.Allocated);
+            _portableIpDao.update(allocatedPortableIp.getId(), allocatedPortableIp);
+
+            // To make portable IP available as a zone level resource we need to emulate portable IP's (which are
+            // provisioned at region level) as public IP provisioned in a zone. user_ip_address and vlan combo give the
+            // identity of a public IP in zone. Create entry for portable ip in these tables.
+
+            // provision portable IP range VLAN into the zone
+            long physicalNetworkId = _networkModel.getDefaultPhysicalNetworkByZoneAndTrafficType(dcId, TrafficType.Public).getId();
+            Network network = _networkModel.getSystemNetworkByZoneAndTrafficType(dcId, TrafficType.Public);
+            String range = allocatedPortableIp.getAddress() + "-" + allocatedPortableIp.getAddress();
+            VlanVO vlan = new VlanVO(VlanType.VirtualNetwork,
+                allocatedPortableIp.getVlan(),
+                allocatedPortableIp.getGateway(),
+                allocatedPortableIp.getNetmask(),
+                dcId,
+                range,
+                network.getId(),
+                physicalNetworkId,
+                null,
+                null,
+                null);
+            vlan = _vlanDao.persist(vlan);
+
+            // provision the portable IP in to user_ip_address table
+            ipaddr = new IPAddressVO(new Ip(allocatedPortableIp.getAddress()), dcId, networkId, vpcID, physicalNetworkId, network.getId(), vlan.getId(), true);
+            ipaddr.setState(State.Allocated);
+            ipaddr.setAllocatedTime(new Date());
+            ipaddr.setAllocatedInDomainId(ipOwner.getDomainId());
+            ipaddr.setAllocatedToAccountId(ipOwner.getId());
+            ipaddr = _ipAddressDao.persist(ipaddr);
+
+            String guestType = vlan.getVlanType().toString();
+            UsageEventUtils.publishUsageEvent(EventTypes.EVENT_PORTABLE_IP_ASSIGN,
+                ipaddr.getId(),
+                ipaddr.getDataCenterId(),
+                ipaddr.getId(),
+                ipaddr.getAddress().toString(),
+                ipaddr.isSourceNat(),
+                null,
+                ipaddr.getSystem(),
+                ipaddr.getClass().getName(),
+                ipaddr.getUuid());
+
+            txn.commit();
+
+        } finally {
+            portableIpLock.unlock();
+        }
+
+        return ipaddr;
+    }
+
+    protected IPAddressVO getExistingSourceNatInNetwork(long ownerId, Long networkId) {
+
+        List<? extends IpAddress> addrs = _networkModel.listPublicIpsAssignedToGuestNtwk(ownerId, networkId, true);
+
+        IPAddressVO sourceNatIp = null;
+        if (addrs.isEmpty()) {
+            return null;
+        } else {
+            // Account already has ip addresses
+            for (IpAddress addr : addrs) {
+                if (addr.isSourceNat()) {
+                    sourceNatIp = _ipAddressDao.findById(addr.getId());
+                    return sourceNatIp;
+                }
+            }
+
+            assert (sourceNatIp != null) : "How do we get a bunch of ip addresses but none of them are source nat? " + "account=" + ownerId + "; networkId=" + networkId;
+        }
+
+        return sourceNatIp;
+    }
+
+    @DB
+    @Override
+    public IPAddressVO associateIPToGuestNetwork(long ipId, long networkId, boolean releaseOnFailure) throws ResourceAllocationException, ResourceUnavailableException,
+        InsufficientAddressCapacityException, ConcurrentOperationException {
+        Account caller = CallContext.current().getCallingAccount();
+        Account owner = null;
+
+        IPAddressVO ipToAssoc = _ipAddressDao.findById(ipId);
+        if (ipToAssoc != null) {
+            Network network = _networksDao.findById(networkId);
+            if (network == null) {
+                throw new InvalidParameterValueException("Invalid network id is given");
+            }
+
+            DataCenter zone = _configMgr.getZone(network.getDataCenterId());
+            if (zone.getNetworkType() == NetworkType.Advanced) {
+                if (network.getGuestType() == Network.GuestType.Shared) {
+                    if (isSharedNetworkOfferingWithServices(network.getNetworkOfferingId())) {
+                        _accountMgr.checkAccess(CallContext.current().getCallingAccount(), AccessType.UseNetwork, false, network);
+                    } else {
+                        throw new InvalidParameterValueException("IP can be associated with guest network of 'shared' type only if "
+                                                                 + "network services Source Nat, Static Nat, Port Forwarding, Load balancing, firewall are enabled in the network");
+                    }
+                }
+            } else {
+                _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;
+        }
+
+        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(owner, AccessType.UseNetwork, false, network);
+        } else {
+            s_logger.debug("Unable to find ip address by id: " + ipId);
+            return null;
+        }
+
+        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);
+        }
+
+        // Check that network belongs to IP owner - skip this check
+        //     - if zone is basic zone as there is just one guest network,
+        //     - if shared network in Advanced zone
+        //     - and it belongs to the system
+        if (network.getAccountId() != owner.getId()) {
+            if (zone.getNetworkType() != NetworkType.Basic && !(zone.getNetworkType() == NetworkType.Advanced && network.getGuestType() == Network.GuestType.Shared)) {
+                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
+        //      - for shared networks with source nat service enabled
+        if (zone.getNetworkType() == NetworkType.Advanced && !(_networkModel.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 (getExistingSourceNatInNetwork(owner.getId(), networkId) == null) {
+                if (network.getGuestType() == GuestType.Isolated && network.getVpcId() == null && !ipToAssoc.isPortable()) {
+                    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() + " to network " + network);
+            } else {
+                s_logger.warn("Failed to associate ip address " + ip.getAddress().addr() + " to network " + network);
+            }
+            return ip;
+        } finally {
+            if (!success && releaseOnFailure) {
+                if (ip != null) {
+                    try {
+                        s_logger.warn("Failed to associate ip address, so releasing ip from the database " + ip);
+                        _ipAddressDao.markAsUnavailable(ip.getId());
+                        if (!applyIpAssociations(network, true)) {
+                            // if fail to apply ip assciations again, unassign ip address without updating resource
+                            // count and generating usage event as there is no need to keep it in the db
+                            _ipAddressDao.unassignIpAddress(ip.getId());
+                        }
+                    } catch (Exception e) {
+                        s_logger.warn("Unable to disassociate ip address for recovery", e);
+                    }
+                }
+            }
+        }
+    }
+
+    protected boolean isSharedNetworkOfferingWithServices(long networkOfferingId) {
+        NetworkOfferingVO networkOffering = _networkOfferingDao.findById(networkOfferingId);
+        if ((networkOffering.getGuestType() == Network.GuestType.Shared) &&
+            (_networkModel.areServicesSupportedByNetworkOffering(networkOfferingId, Service.SourceNat) ||
+             _networkModel.areServicesSupportedByNetworkOffering(networkOfferingId, Service.StaticNat) ||
+             _networkModel.areServicesSupportedByNetworkOffering(networkOfferingId, Service.Firewall) ||
+             _networkModel.areServicesSupportedByNetworkOffering(networkOfferingId, Service.PortForwarding) || _networkModel.areServicesSupportedByNetworkOffering(networkOfferingId,
+                Service.Lb))) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public IPAddressVO associatePortableIPToGuestNetwork(long ipAddrId, long networkId, boolean releaseOnFailure) throws ResourceAllocationException, ResourceUnavailableException,
+        InsufficientAddressCapacityException, ConcurrentOperationException {
+        return associateIPToGuestNetwork(ipAddrId, networkId, releaseOnFailure);
+    }
+
+    @DB
+    @Override
+    public IPAddressVO disassociatePortableIPToGuestNetwork(long ipId, long networkId) throws ResourceAllocationException, ResourceUnavailableException,
+        InsufficientAddressCapacityException, ConcurrentOperationException {
+
+        Account caller = CallContext.current().getCallingAccount();
+        Account owner = null;
+
+        Network network = _networksDao.findById(networkId);
+        if (network == null) {
+            throw new InvalidParameterValueException("Invalid network id is given");
+        }
+
+        IPAddressVO ipToAssoc = _ipAddressDao.findById(ipId);
+        if (ipToAssoc != null) {
+
+            if (ipToAssoc.getAssociatedWithNetworkId() == null) {
+                throw new InvalidParameterValueException("IP " + ipToAssoc + " is not associated with any network");
+            }
+
+            if (ipToAssoc.getAssociatedWithNetworkId() != network.getId()) {
+                throw new InvalidParameterValueException("IP " + ipToAssoc + " is not associated with network id" + networkId);
+            }
+
+            DataCenter zone = _configMgr.getZone(network.getDataCenterId());
+            if (zone.getNetworkType() == NetworkType.Advanced) {
+                if (network.getGuestType() == Network.GuestType.Shared) {
+                    assert (isSharedNetworkOfferingWithServices(network.getNetworkOfferingId()));
+                    _accountMgr.checkAccess(CallContext.current().getCallingAccount(), AccessType.UseNetwork, false, network);
+                }
+            } else {
+                _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;
+        }
+
+        DataCenter zone = _configMgr.getZone(network.getDataCenterId());
+
+        // Check that network belongs to IP owner - skip this check
+        //     - if zone is basic zone as there is just one guest network,
+        //     - if shared network in Advanced zone
+        //     - and it belongs to the system
+        if (network.getAccountId() != owner.getId()) {
+            if (zone.getNetworkType() != NetworkType.Basic && !(zone.getNetworkType() == NetworkType.Advanced && network.getGuestType() == Network.GuestType.Shared)) {
+                throw new InvalidParameterValueException("The owner of the network is not the same as owner of the IP");
+            }
+        }
+
+        // Check if IP has any services (rules) associated in the network
+        List<PublicIpAddress> ipList = new ArrayList<PublicIpAddress>();
+        PublicIp publicIp = PublicIp.createFromAddrAndVlan(ipToAssoc, _vlanDao.findById(ipToAssoc.getVlanId()));
+        ipList.add(publicIp);
+        Map<PublicIpAddress, Set<Service>> ipToServices = _networkModel.getIpToServices(ipList, false, true);
+        if (ipToServices != null & !ipToServices.isEmpty()) {
+            Set<Service> services = ipToServices.get(publicIp);
+            if (services != null && !services.isEmpty()) {
+                throw new InvalidParameterValueException("IP " + ipToAssoc + " has services and rules associated in the network " + networkId);
+            }
+        }
+
+        IPAddressVO ip = _ipAddressDao.findById(ipId);
+        ip.setAssociatedWithNetworkId(null);
+        _ipAddressDao.update(ipId, ip);
+
+        try {
+            boolean success = applyIpAssociations(network, false);
+            if (success) {
+                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() + " to network " + network);
+            }
+            return ip;
+        } finally {
+
+        }
+    }
+
+    @Override
+    public boolean isPortableIpTransferableFromNetwork(long ipAddrId, long networkId) {
+        Network network = _networksDao.findById(networkId);
+        if (network == null) {
+            throw new InvalidParameterValueException("Invalid network id is given");
+        }
+
+        IPAddressVO ip = _ipAddressDao.findById(ipAddrId);
+        if (ip == null) {
+            throw new InvalidParameterValueException("Invalid network id is given");
+        }
+
+        // Check if IP has any services (rules) associated in the network
+        List<PublicIpAddress> ipList = new ArrayList<PublicIpAddress>();
+        PublicIp publicIp = PublicIp.createFromAddrAndVlan(ip, _vlanDao.findById(ip.getVlanId()));
+        ipList.add(publicIp);
+        Map<PublicIpAddress, Set<Service>> ipToServices = _networkModel.getIpToServices(ipList, false, true);
+        if (ipToServices != null & !ipToServices.isEmpty()) {
+            Set<Service> ipServices = ipToServices.get(publicIp);
+            if (ipServices != null && !ipServices.isEmpty()) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    @DB
+    @Override
+    public void transferPortableIP(long ipAddrId, long currentNetworkId, long newNetworkId) throws ResourceAllocationException, ResourceUnavailableException,
+        InsufficientAddressCapacityException, ConcurrentOperationException {
+
+        Network srcNetwork = _networksDao.findById(currentNetworkId);
+        if (srcNetwork == null) {
+            throw new InvalidParameterValueException("Invalid source network id " + currentNetworkId + " is given");
+        }
+
+        Network dstNetwork = _networksDao.findById(newNetworkId);
+        if (dstNetwork == null) {
+            throw new InvalidParameterValueException("Invalid source network id " + newNetworkId + " is given");
+        }
+
+        IPAddressVO ip = _ipAddressDao.findById(ipAddrId);
+        if (ip == null) {
+            throw new InvalidParameterValueException("Invalid portable ip address id is given");
+        }
+
+        Transaction txn = Transaction.currentTxn();
+
+        assert (isPortableIpTransferableFromNetwork(ipAddrId, currentNetworkId));
+
+        // disassociate portable IP with current network/VPC network
+        if (srcNetwork.getVpcId() != null) {
+            _vpcMgr.unassignIPFromVpcNetwork(ipAddrId, currentNetworkId);
+        } else {
+            disassociatePortableIPToGuestNetwork(ipAddrId, currentNetworkId);
+        }
+
+        // If portable IP need to be transferred across the zones, then mark the entry corresponding to portable ip
+        // in user_ip_address and vlan tables so as to emulate portable IP as provisioned in destination data center
+        if (srcNetwork.getDataCenterId() != dstNetwork.getDataCenterId()) {
+            txn.start();
+
+            long physicalNetworkId = _networkModel.getDefaultPhysicalNetworkByZoneAndTrafficType(dstNetwork.getDataCenterId(), TrafficType.Public).getId();
+            long publicNetworkId = _networkModel.getSystemNetworkByZoneAndTrafficType(dstNetwork.getDataCenterId(), TrafficType.Public).getId();
+
+            ip.setDataCenterId(dstNetwork.getDataCenterId());
+            ip.setPhysicalNetworkId(physicalNetworkId);
+            ip.setSourceNetworkId(publicNetworkId);
+            _ipAddressDao.update(ipAddrId, ip);
+
+            VlanVO vlan = _vlanDao.findById(ip.getVlanId());
+            vlan.setPhysicalNetworkId(physicalNetworkId);
+            vlan.setNetworkId(publicNetworkId);
+            vlan.setDataCenterId(dstNetwork.getDataCenterId());
+            _vlanDao.update(ip.getVlanId(), vlan);
+
+            txn.commit();
+        }
+
+        // associate portable IP with new network/VPC network
+        associatePortableIPToGuestNetwork(ipAddrId, newNetworkId, false);
+
+        txn.start();
+
+        if (dstNetwork.getVpcId() != null) {
+            ip.setVpcId(dstNetwork.getVpcId());
+        } else {
+            ip.setVpcId(null);
+        }
+
+        _ipAddressDao.update(ipAddrId, ip);
+
+        txn.commit();
+
+        // trigger an action event for the transfer of portable IP across the networks, so that external entities
+        // monitoring for this event can initiate the route advertisement for the availability of IP from the zoe
+        ActionEventUtils.onActionEvent(User.UID_SYSTEM,
+            Account.ACCOUNT_ID_SYSTEM,
+            Domain.ROOT_DOMAIN,
+            EventTypes.EVENT_PORTABLE_IP_TRANSFER,
+            "Portable IP associated is transferred from network " + currentNetworkId + " to " + newNetworkId);
+    }
+
+    protected List<? extends Network> getIsolatedNetworksWithSourceNATOwnedByAccountInZone(long zoneId, Account owner) {
+
+        return _networksDao.listSourceNATEnabledNetworks(owner.getId(), zoneId, Network.GuestType.Isolated);
+    }
+
+    @Override
+    @DB
+    public boolean associateIpAddressListToAccount(long userId, long accountId, long zoneId, Long vlanId, Network guestNetwork) throws InsufficientCapacityException,
+        ConcurrentOperationException, ResourceUnavailableException, ResourceAllocationException {
+        Account owner = _accountMgr.getActiveAccountById(accountId);
+        boolean createNetwork = false;
+
+        if (guestNetwork != null && guestNetwork.getTrafficType() != TrafficType.Guest) {
+            throw new InvalidParameterValueException("Network " + guestNetwork + " is not of a type " + TrafficType.Guest);
+        }
+
+        Transaction txn = Transaction.currentTxn();
+        txn.start();
+
+        if (guestNetwork == null) {
+            List<? extends Network> networks = getIsolatedNetworksWithSourceNATOwnedByAccountInZone(zoneId, owner);
+            if (networks.size() == 0) {
+                createNetwork = true;
+            } else if (networks.size() == 1) {
+                guestNetwork = networks.get(0);
+            } else {
+                throw new InvalidParameterValueException("Error, more than 1 Guest Isolated Networks with SourceNAT "
+                                                         + "service enabled found for this account, cannot assosiate the IP range, please provide the network ID");
+            }
+        }
+
+        // create new Virtual network (Isolated with SourceNAT) for the user if it doesn't exist
+        List<NetworkOfferingVO> requiredOfferings = _networkOfferingDao.listByAvailability(Availability.Required, false);
+        if (requiredOfferings.size() < 1) {
+            throw new CloudRuntimeException("Unable to find network offering with availability=" + Availability.Required +
+                                            " to automatically create the network as part of createVlanIpRange");
+        }
+        if (createNetwork) {
+            if (requiredOfferings.get(0).getState() == NetworkOffering.State.Enabled) {
+                long physicalNetworkId = _networkModel.findPhysicalNetworkId(zoneId, requiredOfferings.get(0).getTags(), requiredOfferings.get(0).getTrafficType());
+                // Validate physical network
+                PhysicalNetwork physicalNetwork = _physicalNetworkDao.findById(physicalNetworkId);
+                if (physicalNetwork == null) {
+                    throw new InvalidParameterValueException("Unable to find physical network with id: " + physicalNetworkId + " and tag: " + requiredOfferings.get(0).getTags());
+                }
+
+                s_logger.debug("Creating network for account " + owner + " from the network offering id=" + requiredOfferings.get(0).getId() +
+                               " as a part of createVlanIpRange process");
+                guestNetwork = _networkMgr.createGuestNetwork(requiredOfferings.get(0).getId(),
+                    owner.getAccountName() + "-network",
+                    owner.getAccountName() + "-network",
+                    null,
+                    null,
+                    null,
+                    null,
+                    owner,
+                    null,
+                    physicalNetwork,
+                    zoneId,
+                    ACLType.Account,
+                    null,
+                    null,
+                    null,
+                    null,
+                    true,
+                    null);
+                if (guestNetwork == null) {
+                    s_logger.warn("Failed to create default Virtual network for the account " + accountId + "in zone " + zoneId);
+                    throw new CloudRuntimeException("Failed to create a Guest Isolated Networks with SourceNAT " +
+                                                    "service enabled as a part of createVlanIpRange, for the account " + accountId + "in zone " + zoneId);
+                }
+            } else {
+                throw new CloudRuntimeException("Required network offering id=" + requiredOfferings.get(0).getId() + " is not in " + NetworkOffering.State.Enabled);
+            }
+        }
+
+        // Check if there is a source nat ip address for this account; if not - we have to allocate one
+        boolean allocateSourceNat = false;
+        List<IPAddressVO> sourceNat = _ipAddressDao.listByAssociatedNetwork(guestNetwork.getId(), true);
+        if (sourceNat.isEmpty()) {
+            allocateSourceNat = true;
+        }
+
+        // update all ips with a network id, mark them as allocated and update resourceCount/usage
+        List<IPAddressVO> ips = _ipAddressDao.listByVlanId(vlanId);
+        boolean isSourceNatAllocated = false;
+        for (IPAddressVO addr : ips) {
+            if (addr.getState() != State.Allocated) {
+                if (!isSourceNatAllocated && allocateSourceNat) {
+                    addr.setSourceNat(true);
+                    isSourceNatAllocated = true;
+                } else {
+                    addr.setSourceNat(false);
+                }
+                addr.setAssociatedWithNetworkId(guestNetwork.getId());
+                addr.setVpcId(guestNetwork.getVpcId());
+                addr.setAllocatedTime(new Date());
+                addr.setAllocatedInDomainId(owner.getDomainId());
+                addr.setAllocatedToAccountId(owner.getId());
+                addr.setSystem(false);
+                addr.setState(IpAddress.State.Allocating);
+                markPublicIpAsAllocated(addr);
+            }
+        }
+
+        txn.commit();
+
+        // if the network offering has persistent set to true, implement the network
+        if (createNetwork && requiredOfferings.get(0).getIsPersistent()) {
+            DataCenter zone = _dcDao.findById(zoneId);
+            DeployDestination dest = new DeployDestination(zone, null, null, null);
+            Account callerAccount = CallContext.current().getCallingAccount();
+            UserVO callerUser = _userDao.findById(CallContext.current().getCallingUserId());
+            Journal journal = new Journal.LogJournal("Implementing " + guestNetwork, s_logger);
+            ReservationContext context = new ReservationContextImpl(UUID.randomUUID().toString(), journal, callerUser, callerAccount);
+            s_logger.debug("Implementing network " + guestNetwork + " as a part of network provision for persistent network");
+            try {
+                Pair<NetworkGuru, NetworkVO> implementedNetwork = _networkMgr.implementNetwork(guestNetwork.getId(), dest, context);
+                if (implementedNetwork.first() == null) {
+                    s_logger.warn("Failed to implement the network " + guestNetwork);
+                }
+                guestNetwork = implementedNetwork.second();
+            } catch (Exception ex) {
+                s_logger.warn("Failed to implement network " + guestNetwork + " elements and resources as a part of" + " network provision due to ", ex);
+                CloudRuntimeException e = new CloudRuntimeException("Failed to implement network (with specified id)"
+                                                                    + " elements and resources as a part of network provision for persistent network");
+                e.addProxyObject(guestNetwork.getUuid(), "networkId");
+                throw e;
+            }
+        }
+        return true;
+    }
+
+    @DB
+    @Override
+    public IPAddressVO markIpAsUnavailable(long addrId) {
+        Transaction txn = Transaction.currentTxn();
+
+        IPAddressVO ip = _ipAddressDao.findById(addrId);
+
+        if (ip.getAllocatedToAccountId() == null && ip.getAllocatedTime() == null) {
+            s_logger.trace("Ip address id=" + addrId + " is already released");
+            return ip;
+        }
+
+        if (ip.getState() != State.Releasing) {
+            txn.start();
+
+            // don't decrement resource count for direct and dedicated ips
+            if (ip.getAssociatedWithNetworkId() != null && !isIpDedicated(ip)) {
+                _resourceLimitMgr.decrementResourceCount(_ipAddressDao.findById(addrId).getAllocatedToAccountId(), ResourceType.public_ip);
+            }
+
+            // Save usage event
+            if (ip.getAllocatedToAccountId() != null && ip.getAllocatedToAccountId() != Account.ACCOUNT_ID_SYSTEM) {
+                VlanVO vlan = _vlanDao.findById(ip.getVlanId());
+
+                String guestType = vlan.getVlanType().toString();
+                if (!isIpDedicated(ip)) {
+                    String eventType = ip.isPortable() ? EventTypes.EVENT_PORTABLE_IP_RELEASE : EventTypes.EVENT_NET_IP_RELEASE;
+                    UsageEventUtils.publishUsageEvent(eventType,
+                        ip.getAllocatedToAccountId(),
+                        ip.getDataCenterId(),
+                        addrId,
+                        ip.getAddress().addr(),
+                        ip.isSourceNat(),
+                        guestType,
+                        ip.getSystem(),
+                        ip.getClass().getName(),
+                        ip.getUuid());
+                }
+            }
+
+            ip = _ipAddressDao.markAsUnavailable(addrId);
+
+            txn.commit();
+        }
+
+        return ip;
+    }
+
+    @Override
+    @DB
+    public String acquireGuestIpAddress(Network network, String requestedIp) {
+        if (requestedIp != null && requestedIp.equals(network.getGateway())) {
+            s_logger.warn("Requested ip address " + requestedIp + " is used as a gateway address in network " + network);
+            return null;
+        }
+
+        Set<Long> availableIps = _networkModel.getAvailableIps(network, requestedIp);
+
+        if (availableIps == null || availableIps.isEmpty()) {
+            return null;
+        }
+
+        Long[] array = availableIps.toArray(new Long[availableIps.size()]);
+
+        if (requestedIp != null) {
+            // check that requested ip has the same cidr
+            String[] cidr = network.getCidr().split("/");
+            boolean isSameCidr = NetUtils.sameSubnetCIDR(requestedIp, NetUtils.long2Ip(array[0]), Integer.parseInt(cidr[1]));
+            if (!isSameCidr) {
+                s_logger.warn("Requested ip address " + requestedIp + " doesn't belong to the network " + network + " cidr");
+                return null;
+            } else {
+                return requestedIp;
+            }
+        }
+
+        String result;
+        do {
+            result = NetUtils.long2Ip(array[_rand.nextInt(array.length)]);
+        } while (result.split("\\.")[3].equals("1"));
+        return result;
+    }
+
+    Random _rand = new Random(System.currentTimeMillis());
+
+    @Override
+    public boolean applyStaticNats(List<? extends StaticNat> staticNats, boolean continueOnError, boolean forRevoke) throws ResourceUnavailableException {
+        Network network = _networksDao.findById(staticNats.get(0).getNetworkId());
+        boolean success = true;
+
+        if (staticNats == null || staticNats.size() == 0) {
+            s_logger.debug("There are no static nat rules for the network elements");
+            return true;
+        }
+
+        // get the list of public ip's owned by the network
+        List<IPAddressVO> userIps = _ipAddressDao.listByAssociatedNetwork(network.getId(), null);
+        List<PublicIp> publicIps = new ArrayList<PublicIp>();
+        if (userIps != null && !userIps.isEmpty()) {
+            for (IPAddressVO userIp : userIps) {
+                PublicIp publicIp = PublicIp.createFromAddrAndVlan(userIp, _vlanDao.findById(userIp.getVlanId()));
+                publicIps.add(publicIp);
+            }
+        }
+
+        // static NAT rules can not programmed unless IP is associated with source NAT service provider, so run IP
+        // association for the network so as to ensure IP is associated before applying rules
+        if (checkStaticNatIPAssocRequired(network, false, forRevoke, publicIps)) {
+            applyIpAssociations(network, false, continueOnError, publicIps);
+        }
+
+        // get provider
+        StaticNatServiceProvider element = _networkMgr.getStaticNatProviderForNetwork(network);
+        try {
+            success = element.applyStaticNats(network, staticNats);
+        } catch (ResourceUnavailableException e) {
+            if (!continueOnError) {
+                throw e;
+            }
+            s_logger.warn("Problems with " + element.getName() + " but pushing on", e);
+            success = false;
+        }
+
+        // For revoked static nat IP, set the vm_id to null, indicate it should be revoked
+        for (StaticNat staticNat : staticNats) {
+            if (staticNat.isForRevoke()) {
+                for (PublicIp publicIp : publicIps) {
+                    if (publicIp.getId() == staticNat.getSourceIpAddressId()) {
+                        publicIps.remove(publicIp);
+                        IPAddressVO ip = _ipAddressDao.findByIdIncludingRemoved(staticNat.getSourceIpAddressId());
+                        // ip can't be null, otherwise something wrong happened
+                        ip.setAssociatedWithVmId(null);
+                        publicIp = PublicIp.createFromAddrAndVlan(ip, _vlanDao.findById(ip.getVlanId()));
+                        publicIps.add(publicIp);
+                        break;
+                    }
+                }
+            }
+        }
+
+        // if the static NAT rules configured on public IP is revoked then, dis-associate IP with static NAT service provider
+        if (checkStaticNatIPAssocRequired(network, true, forRevoke, publicIps)) {
+            applyIpAssociations(network, true, continueOnError, publicIps);
+        }
+
+        return success;
+    }
+
+    // checks if there are any public IP assigned to network, that are marked for one-to-one NAT that
+    // needs to be associated/dis-associated with static-nat provider
+    boolean checkStaticNatIPAssocRequired(Network network, boolean postApplyRules, boolean forRevoke, List<PublicIp> publicIps) {
+        for (PublicIp ip : publicIps) {
+            if (ip.isOneToOneNat()) {
+                Long activeFwCount = null;
+                activeFwCount = _firewallDao.countRulesByIpIdAndState(ip.getId(), FirewallRule.State.Active);
+
+                if (!postApplyRules && !forRevoke) {
+                    if (activeFwCount > 0) {
+                        continue;
+                    } else {
+                        return true;
+                    }
+                } else if (postApplyRules && forRevoke) {
+                    return true;
+                }
+            } else {
+                continue;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public IpAddress assignSystemIp(long networkId, Account owner, boolean forElasticLb, boolean forElasticIp) throws InsufficientAddressCapacityException {
+        Network guestNetwork = _networksDao.findById(networkId);
+        NetworkOffering off = _configMgr.getNetworkOffering(guestNetwork.getNetworkOfferingId());
+        IpAddress ip = null;
+        if ((off.getElasticLb() && forElasticLb) || (off.getElasticIp() && forElasticIp)) {
+
+            try {
+                s_logger.debug("Allocating system IP address for load balancer rule...");
+                // allocate ip
+                ip = allocateIP(owner, true, guestNetwork.getDataCenterId());
+                // apply ip associations
+                ip = associateIPToGuestNetwork(ip.getId(), networkId, true);
+                ;
+            } catch (ResourceAllocationException ex) {
+                throw new CloudRuntimeException("Failed to allocate system ip due to ", ex);
+            } catch (ConcurrentOperationException ex) {
+                throw new CloudRuntimeException("Failed to allocate system lb ip due to ", ex);
+            } catch (ResourceUnavailableException ex) {
+                throw new CloudRuntimeException("Failed to allocate system lb ip due to ", ex);
+            }
+
+            if (ip == null) {
+                throw new CloudRuntimeException("Failed to allocate system ip");
+            }
+        }
+
+        return ip;
+    }
+
+    @Override
+    public boolean handleSystemIpRelease(IpAddress ip) {
+        boolean success = true;
+        Long networkId = ip.getAssociatedWithNetworkId();
+        if (networkId != null) {
+            if (ip.getSystem()) {
+                CallContext ctx = CallContext.current();
+                if (!disassociatePublicIpAddress(ip.getId(), ctx.getCallingUserId(), ctx.getCallingAccount())) {
+                    s_logger.warn("Unable to release system ip address id=" + ip.getId());
+                    success = false;
+                } else {
+                    s_logger.warn("Successfully released system ip address id=" + ip.getId());
+                }
+            }
+        }
+        return success;
+    }
+
+    @Override
+    @DB
+    public void allocateDirectIp(NicProfile nic, DataCenter dc, VirtualMachineProfile vm, Network network, String requestedIpv4, String requestedIpv6)
+        throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException {
+        //This method allocates direct ip for the Shared network in Advance zones
+        boolean ipv4 = false;
+
+        Transaction txn = Transaction.currentTxn();
+        txn.start();
+
+        if (network.getGateway() != null) {
+            if (nic.getIp4Address() == null) {
+                ipv4 = true;
+                PublicIp ip = null;
+
+                //Get ip address from the placeholder and don't allocate a new one
+                if (requestedIpv4 != null && vm.getType() == VirtualMachine.Type.DomainRouter) {
+                    Nic placeholderNic = _networkModel.getPlaceholderNicForRouter(network, null);
+                    if (placeholderNic != null) {
+                        IPAddressVO userIp = _ipAddressDao.findByIpAndSourceNetworkId(network.getId(), placeholderNic.getIp4Address());
+                        ip = PublicIp.createFromAddrAndVlan(userIp, _vlanDao.findById(userIp.getVlanId()));
+                        s_logger.debug("Nic got an ip address " + placeholderNic.getIp4Address() + " stored in placeholder nic for the network " + network);
+                    }
+                }
+
+                if (ip == null) {
+                    ip = assignPublicIpAddress(dc.getId(), null, vm.getOwner(), VlanType.DirectAttached, network.getId(), requestedIpv4, false);
+                }
+
+                nic.setIp4Address(ip.getAddress().toString());
+                nic.setGateway(ip.getGateway());
+                nic.setNetmask(ip.getNetmask());
+                nic.setIsolationUri(IsolationType.Vlan.toUri(ip.getVlanTag()));
+                //nic.setBroadcastType(BroadcastDomainType.Vlan);
+                //nic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(ip.getVlanTag()));
+                nic.setBroadcastType(network.getBroadcastDomainType());
+                nic.setBroadcastUri(network.getBroadcastUri());
+   

<TRUNCATED>

Mime
View raw message