cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From muralire...@apache.org
Subject [1/2] CLOUDSTACK-652: meging 'portable public ip' feature
Date Mon, 20 May 2013 14:38:25 GMT
Updated Branches:
  refs/heads/master f5c8e386e -> d6452be86


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/server/src/com/cloud/network/NetworkServiceImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java
index ed9a8c4..1533ca9 100755
--- a/server/src/com/cloud/network/NetworkServiceImpl.java
+++ b/server/src/com/cloud/network/NetworkServiceImpl.java
@@ -39,6 +39,7 @@ import javax.ejb.Local;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import com.cloud.network.vpc.dao.VpcDao;
 import org.apache.cloudstack.acl.ControlledEntity.ACLType;
 import org.apache.cloudstack.acl.SecurityChecker;
 import org.apache.cloudstack.acl.SecurityChecker.AccessType;
@@ -184,32 +185,6 @@ import com.cloud.vm.dao.NicSecondaryIpDao;
 import com.cloud.vm.dao.NicSecondaryIpVO;
 import com.cloud.vm.dao.UserVmDao;
 import com.cloud.vm.dao.VMInstanceDao;
-import com.cloud.vm.*;
-import com.cloud.vm.dao.*;
-import org.apache.cloudstack.acl.ControlledEntity.ACLType;
-import org.apache.cloudstack.acl.SecurityChecker;
-import org.apache.cloudstack.acl.SecurityChecker.AccessType;
-import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd;
-import org.apache.cloudstack.api.command.admin.network.ListDedicatedGuestVlanRangesCmd;
-import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd;
-import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd;
-import org.apache.cloudstack.api.command.user.network.ListNetworksCmd;
-import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd;
-import org.apache.cloudstack.api.command.user.vm.ListNicsCmd;
-import org.apache.log4j.Logger;
-import org.springframework.stereotype.Component;
-
-import javax.ejb.Local;
-import javax.inject.Inject;
-import javax.naming.ConfigurationException;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.security.InvalidParameterException;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.*;
 
 
 /**
@@ -315,6 +290,8 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
     @Inject
     AccountGuestVlanMapDao _accountGuestVlanMapDao;
     @Inject
+    VpcDao _vpcDao;
+    @Inject
     NetworkACLDao _networkACLDao;
 
     int _cidrLimit;
@@ -527,22 +504,23 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
     public IpAddress allocateIP(Account ipOwner, long zoneId, Long networkId)
              throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException {
 
+        Account caller = UserContext.current().getCaller();
+        long callerUserId = UserContext.current().getCallerUserId();
+        DataCenter zone = _configMgr.getZone(zoneId);
+
         if (networkId != null) {
             Network network = _networksDao.findById(networkId);
             if (network == null) {
                 throw new InvalidParameterValueException("Invalid network id is given");
             }
+
             if (network.getGuestType() == Network.GuestType.Shared) {
-                DataCenter zone = _configMgr.getZone(zoneId);
                 if (zone == null) {
                     throw new InvalidParameterValueException("Invalid zone Id is given");
                 }
-
                 // if shared network in the advanced zone, then check the caller against the network for 'AccessType.UseNetwork'
                 if (zone.getNetworkType() == NetworkType.Advanced) {
                     if (isSharedNetworkOfferingWithServices(network.getNetworkOfferingId())) {
-                        Account caller = UserContext.current().getCaller();
-                        long callerUserId = UserContext.current().getCallerUserId();
                         _accountMgr.checkAccess(caller, AccessType.UseNetwork, false, network);
                         if (s_logger.isDebugEnabled()) {
                             s_logger.debug("Associate IP address called by the user " + callerUserId + " account " + ipOwner.getId());
@@ -554,20 +532,67 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
                     }
                 }
             }
+        } else {
+            _accountMgr.checkAccess(caller, null, false, ipOwner);
         }
 
-        return allocateIP(ipOwner, false,  zoneId);
+        return _networkMgr.allocateIp(ipOwner, false, caller, callerUserId, zone);
     }
 
-    public IpAddress allocateIP(Account ipOwner, boolean isSystem, long zoneId)
+    @Override
+    @ActionEvent(eventType = EventTypes.EVENT_PORTABLE_IP_ASSIGN, eventDescription = "allocating portable public Ip", create = true)
+    public IpAddress allocatePortableIP(Account ipOwner, int regionId, Long zoneId, Long networkId, Long vpcId)
             throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException {
         Account caller = UserContext.current().getCaller();
-        // check permissions
-        _accountMgr.checkAccess(caller, null, false, ipOwner);
         long callerUserId = UserContext.current().getCallerUserId();
         DataCenter zone = _configMgr.getZone(zoneId);
 
-        return _networkMgr.allocateIp(ipOwner, isSystem, caller, callerUserId, zone);
+        if ((networkId == null && vpcId == null) && (networkId != null && vpcId != null)) {
+            throw new InvalidParameterValueException("One of Network id or VPC is should be passed");
+        }
+
+        if (networkId != null) {
+            Network network = _networksDao.findById(networkId);
+            if (network == null) {
+                throw new InvalidParameterValueException("Invalid network id is given");
+            }
+
+            if (network.getGuestType() == Network.GuestType.Shared) {
+                if (zone == null) {
+                    throw new InvalidParameterValueException("Invalid zone Id is given");
+                }
+                // if shared network in the advanced zone, then check the caller against the network for 'AccessType.UseNetwork'
+                if (zone.getNetworkType() == NetworkType.Advanced) {
+                    if (isSharedNetworkOfferingWithServices(network.getNetworkOfferingId())) {
+                        _accountMgr.checkAccess(caller, AccessType.UseNetwork, false, network);
+                        if (s_logger.isDebugEnabled()) {
+                            s_logger.debug("Associate IP address called by the user " + callerUserId + " account " + ipOwner.getId());
+                        }
+                        return _networkMgr.allocatePortableIp(ipOwner, caller, zoneId, networkId, null);
+                    } else {
+                        throw new InvalidParameterValueException("Associate IP address can only be called on the shared networks in the advanced zone" +
+                                " with Firewall/Source Nat/Static Nat/Port Forwarding/Load balancing services enabled");
+                    }
+                }
+            }
+        }
+
+        if (vpcId != null) {
+            Vpc vpc = _vpcDao.findById(vpcId);
+            if (vpc != null) {
+                throw new InvalidParameterValueException("Invalid vpc id is given");
+            }
+        }
+
+        _accountMgr.checkAccess(caller, null, false, ipOwner);
+
+        return _networkMgr.allocatePortableIp(ipOwner, caller, zoneId, null, null);
+    }
+
+    @Override
+    @ActionEvent(eventType = EventTypes.EVENT_PORTABLE_IP_RELEASE, eventDescription = "disassociating portable Ip", async = true)
+    public boolean releasePortableIpAddress(long ipAddressId) throws InsufficientAddressCapacityException {
+        return releaseIpAddressInternal(ipAddressId);
     }
 
     @Override
@@ -810,9 +835,13 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
     }
 
     @Override
-    @DB
     @ActionEvent(eventType = EventTypes.EVENT_NET_IP_RELEASE, eventDescription = "disassociating Ip", async = true)
     public boolean releaseIpAddress(long ipAddressId) throws InsufficientAddressCapacityException {
+        return releaseIpAddressInternal(ipAddressId);
+    }
+
+    @DB
+    private boolean releaseIpAddressInternal(long ipAddressId) throws InsufficientAddressCapacityException {
         Long userId = UserContext.current().getCallerUserId();
         Account caller = UserContext.current().getCaller();
 
@@ -851,6 +880,9 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
         boolean success = _networkMgr.disassociatePublicIpAddress(ipAddressId, userId, caller);
 
         if (success) {
+            if (!ipVO.isPortable()) {
+                return success;
+            }
             Long networkId = ipVO.getAssociatedWithNetworkId();
             if (networkId != null) {
                 Network guestNetwork = getNetwork(networkId);
@@ -867,7 +899,6 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
         return success;
     }
 
-
     @Override
     @DB
     public Network getNetwork(long id) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/server/src/com/cloud/network/addr/PublicIp.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/addr/PublicIp.java b/server/src/com/cloud/network/addr/PublicIp.java
index c753b49..b18c691 100644
--- a/server/src/com/cloud/network/addr/PublicIp.java
+++ b/server/src/com/cloud/network/addr/PublicIp.java
@@ -220,6 +220,15 @@ public class PublicIp implements PublicIpAddress {
         return _addr.getVmIp();
     }
 
+    @Override
+    public boolean isPortable() {
+        return _addr.isPortable();
+    }
+
+    public void setPortable(boolean portable) {
+        _addr.setPortable(portable);
+    }
+
     public Long getIpMacAddress() {
         return  _addr.getMacAddress();
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/server/src/com/cloud/network/rules/RulesManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/rules/RulesManagerImpl.java b/server/src/com/cloud/network/rules/RulesManagerImpl.java
index c9b47b4..8834553 100755
--- a/server/src/com/cloud/network/rules/RulesManagerImpl.java
+++ b/server/src/com/cloud/network/rules/RulesManagerImpl.java
@@ -491,6 +491,49 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
                             return false;
                         }
                         performedIpAssoc = true;
+                    }  else if (ipAddress.isPortable()) {
+                        s_logger.info("Portable IP " + ipAddress.getUuid() + " is not associated with the network, so" +
+                                "associate IP with the network " + networkId);
+                        try {
+                            // check if StaticNat service is enabled in the network
+                            _networkModel.checkIpForService(ipAddress, Service.StaticNat, networkId);
+
+                            // associate portable IP to vpc, if network is part of VPC
+                            if (network.getVpcId() != null) {
+                                _vpcMgr.associateIPToVpc(ipId, network.getVpcId());
+                            }
+
+                            // associate portable IP with guest network
+                            _networkMgr.associatePortableIPToGuestNetwork(ipId, networkId, false);
+                        } catch (Exception e) {
+                            s_logger.warn("Failed to associate portable id=" + ipId + " to network id=" + networkId + " as " +
+                                    "a part of enable static nat");
+                            return false;
+                        }
+                        performedIpAssoc = true;
+                    }
+                } else  if (ipAddress.getAssociatedWithNetworkId() != networkId) {
+                    if (ipAddress.isPortable()) {
+                        // check if destination network has StaticNat service enabled
+                        _networkModel.checkIpForService(ipAddress, Service.StaticNat, networkId);
+
+                        // check if portable IP can be transferred across the networks
+                        if (_networkMgr.isPortableIpTransferableFromNetwork(ipId, ipAddress.getAssociatedWithNetworkId() )) {
+                            try {
+                                _networkMgr.transferPortableIP(ipId, ipAddress.getAssociatedWithNetworkId(), networkId);
+                            } catch (Exception e) {
+                                s_logger.warn("Failed to associate portable id=" + ipId + " to network id=" + networkId + " as " +
+                                        "a part of enable static nat");
+                                return false;
+                            }
+                        } else {
+                            throw new InvalidParameterValueException("Portable IP: " + ipId + " has associated services" +
+                                    "in network " + ipAddress.getAssociatedWithNetworkId() + " so can not be transferred to " +
+                                    " network " + networkId);
+                        }
+                    } else {
+                        throw new InvalidParameterValueException("Invalid network Id=" + networkId + ". IP is associated with"
+                            + " a different network than passed network id");
                     }
                 } else {
                     _networkModel.checkIpForService(ipAddress, Service.StaticNat, null);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/server/src/com/cloud/server/ManagementServerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java
index 8b3eea4..8323af8 100755
--- a/server/src/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/com/cloud/server/ManagementServerImpl.java
@@ -47,6 +47,14 @@ import com.cloud.exception.*;
 import com.cloud.vm.*;
 import org.apache.cloudstack.acl.ControlledEntity;
 import org.apache.cloudstack.acl.SecurityChecker.AccessType;
+import org.apache.cloudstack.api.ApiConstants;
+
+import com.cloud.event.ActionEventUtils;
+import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoCmd;
+import org.apache.cloudstack.api.command.admin.region.*;
+import org.apache.cloudstack.api.response.ExtractResponse;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.log4j.Logger;
 import org.apache.cloudstack.affinity.AffinityGroupProcessor;
 import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
 import org.apache.cloudstack.api.ApiConstants;
@@ -124,9 +132,6 @@ import org.apache.cloudstack.api.command.admin.pod.CreatePodCmd;
 import org.apache.cloudstack.api.command.admin.pod.DeletePodCmd;
 import org.apache.cloudstack.api.command.admin.pod.ListPodsByCmd;
 import org.apache.cloudstack.api.command.admin.pod.UpdatePodCmd;
-import org.apache.cloudstack.api.command.admin.region.AddRegionCmd;
-import org.apache.cloudstack.api.command.admin.region.RemoveRegionCmd;
-import org.apache.cloudstack.api.command.admin.region.UpdateRegionCmd;
 import org.apache.cloudstack.api.command.admin.resource.ArchiveAlertsCmd;
 import org.apache.cloudstack.api.command.admin.resource.DeleteAlertsCmd;
 import org.apache.cloudstack.api.command.admin.resource.ListAlertsCmd;
@@ -571,8 +576,78 @@ import com.cloud.vm.dao.VMInstanceDao;
 
 import edu.emory.mathcs.backport.java.util.Arrays;
 import edu.emory.mathcs.backport.java.util.Collections;
-import org.apache.cloudstack.api.command.admin.config.ListDeploymentPlannersCmd;
 
+import org.apache.cloudstack.acl.ControlledEntity;
+import org.apache.cloudstack.api.command.admin.autoscale.CreateCounterCmd;
+import org.apache.cloudstack.api.command.admin.autoscale.DeleteCounterCmd;
+import org.apache.cloudstack.api.command.admin.cluster.AddClusterCmd;
+import org.apache.cloudstack.api.command.admin.cluster.DeleteClusterCmd;
+import org.apache.cloudstack.api.command.admin.cluster.ListClustersCmd;
+import org.apache.cloudstack.api.command.admin.cluster.UpdateClusterCmd;
+import org.apache.cloudstack.api.command.admin.config.ListCfgsByCmd;
+import org.apache.cloudstack.api.command.admin.config.ListHypervisorCapabilitiesCmd;
+import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd;
+import org.apache.cloudstack.api.command.admin.config.UpdateHypervisorCapabilitiesCmd;
+import org.apache.cloudstack.api.command.admin.ldap.LDAPConfigCmd;
+import org.apache.cloudstack.api.command.admin.ldap.LDAPRemoveCmd;
+import org.apache.cloudstack.api.command.admin.pod.CreatePodCmd;
+import org.apache.cloudstack.api.command.admin.pod.DeletePodCmd;
+import org.apache.cloudstack.api.command.admin.pod.ListPodsByCmd;
+import org.apache.cloudstack.api.command.admin.pod.UpdatePodCmd;
+import org.apache.cloudstack.api.command.admin.swift.AddSwiftCmd;
+import org.apache.cloudstack.api.command.admin.swift.ListSwiftsCmd;
+import org.apache.cloudstack.api.command.admin.template.PrepareTemplateCmd;
+import org.apache.cloudstack.api.command.admin.vlan.CreateVlanIpRangeCmd;
+import org.apache.cloudstack.api.command.admin.vlan.DeleteVlanIpRangeCmd;
+import org.apache.cloudstack.api.command.admin.vlan.ListVlanIpRangesCmd;
+import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd;
+import org.apache.cloudstack.api.command.admin.vm.MigrateVMCmd;
+import org.apache.cloudstack.api.command.admin.vm.MigrateVirtualMachineWithVolumeCmd;
+import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd;
+import org.apache.cloudstack.api.command.admin.zone.CreateZoneCmd;
+import org.apache.cloudstack.api.command.admin.zone.DeleteZoneCmd;
+import org.apache.cloudstack.api.command.admin.zone.MarkDefaultZoneForAccountCmd;
+import org.apache.cloudstack.api.command.admin.zone.UpdateZoneCmd;
+import org.apache.cloudstack.api.command.user.account.AddAccountToProjectCmd;
+import org.apache.cloudstack.api.command.user.account.DeleteAccountFromProjectCmd;
+import org.apache.cloudstack.api.command.user.account.ListAccountsCmd;
+import org.apache.cloudstack.api.command.user.account.ListProjectAccountsCmd;
+import org.apache.cloudstack.api.command.user.address.AssociateIPAddrCmd;
+import org.apache.cloudstack.api.command.user.address.DisassociateIPAddrCmd;
+import org.apache.cloudstack.api.command.user.address.ListPublicIpAddressesCmd;
+import org.apache.cloudstack.api.command.user.config.ListCapabilitiesCmd;
+import org.apache.cloudstack.api.command.user.event.ArchiveEventsCmd;
+import org.apache.cloudstack.api.command.user.event.DeleteEventsCmd;
+import org.apache.cloudstack.api.command.user.event.ListEventTypesCmd;
+import org.apache.cloudstack.api.command.user.event.ListEventsCmd;
+import org.apache.cloudstack.api.command.user.guest.ListGuestOsCategoriesCmd;
+import org.apache.cloudstack.api.command.user.guest.ListGuestOsCmd;
+import org.apache.cloudstack.api.command.user.job.ListAsyncJobsCmd;
+import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd;
+import org.apache.cloudstack.api.command.user.offering.ListDiskOfferingsCmd;
+import org.apache.cloudstack.api.command.user.offering.ListServiceOfferingsCmd;
+import org.apache.cloudstack.api.command.user.region.ListRegionsCmd;
+import org.apache.cloudstack.api.command.user.region.ha.gslb.*;
+import org.apache.cloudstack.api.command.user.ssh.CreateSSHKeyPairCmd;
+import org.apache.cloudstack.api.command.user.ssh.DeleteSSHKeyPairCmd;
+import org.apache.cloudstack.api.command.user.ssh.ListSSHKeyPairsCmd;
+import org.apache.cloudstack.api.command.user.ssh.RegisterSSHKeyPairCmd;
+import org.apache.cloudstack.api.command.user.tag.CreateTagsCmd;
+import org.apache.cloudstack.api.command.user.tag.DeleteTagsCmd;
+import org.apache.cloudstack.api.command.user.tag.ListTagsCmd;
+import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd;
+import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd;
+import org.apache.cloudstack.api.command.user.vmgroup.ListVMGroupsCmd;
+import org.apache.cloudstack.api.command.user.vmgroup.UpdateVMGroupCmd;
+import org.apache.cloudstack.api.command.user.vmsnapshot.CreateVMSnapshotCmd;
+import org.apache.cloudstack.api.command.user.vmsnapshot.DeleteVMSnapshotCmd;
+import org.apache.cloudstack.api.command.user.vmsnapshot.ListVMSnapshotCmd;
+import org.apache.cloudstack.api.command.user.zone.ListZonesByCmd;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
+import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator;
+import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
+import org.apache.cloudstack.api.command.admin.config.ListDeploymentPlannersCmd;
 
 public class ManagementServerImpl extends ManagerBase implements ManagementServer {
     public static final Logger s_logger = Logger.getLogger(ManagementServerImpl.class.getName());
@@ -2897,6 +2972,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
         cmdList.add(ListAffinityGroupsCmd.class);
         cmdList.add(UpdateVMAffinityGroupCmd.class);
         cmdList.add(ListAffinityGroupTypesCmd.class);
+        cmdList.add(CreatePortableIpRangeCmd.class);
+        cmdList.add(DeletePortableIpRangeCmd.class);
+        cmdList.add(ListPortableIpRangesCmd.class);
         cmdList.add(ListDeploymentPlannersCmd.class);
         cmdList.add(ReleaseHostReservationCmd.class);
         cmdList.add(ScaleSystemVMCmd.class);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/server/src/org/apache/cloudstack/region/PortableIpDao.java
----------------------------------------------------------------------
diff --git a/server/src/org/apache/cloudstack/region/PortableIpDao.java b/server/src/org/apache/cloudstack/region/PortableIpDao.java
new file mode 100755
index 0000000..9f5341f
--- /dev/null
+++ b/server/src/org/apache/cloudstack/region/PortableIpDao.java
@@ -0,0 +1,39 @@
+// 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 org.apache.cloudstack.region;
+
+import java.util.List;
+
+import com.cloud.dc.Vlan;
+import com.cloud.dc.Vlan.VlanType;
+import com.cloud.dc.VlanVO;
+import com.cloud.utils.db.GenericDao;
+
+public interface PortableIpDao  extends GenericDao<PortableIpVO, Long> {
+
+    List<PortableIpVO> listByRegionId(int regionId);
+
+    List<PortableIpVO> listByRangeId(long rangeId);
+
+    List<PortableIpVO> listByRangeIdAndState(long rangeId, PortableIp.State state);
+
+    List<PortableIpVO> listByRegionIdAndState(int regionId, PortableIp.State state);
+
+    PortableIpVO findByIpAddress(String ipAddress);
+
+    void unassignIpAddress(long ipAddressId);
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/server/src/org/apache/cloudstack/region/PortableIpDaoImpl.java
----------------------------------------------------------------------
diff --git a/server/src/org/apache/cloudstack/region/PortableIpDaoImpl.java b/server/src/org/apache/cloudstack/region/PortableIpDaoImpl.java
new file mode 100755
index 0000000..488761b
--- /dev/null
+++ b/server/src/org/apache/cloudstack/region/PortableIpDaoImpl.java
@@ -0,0 +1,131 @@
+// 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 org.apache.cloudstack.region;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.ejb.Local;
+import javax.inject.Inject;
+import javax.naming.ConfigurationException;
+
+import org.springframework.stereotype.Component;
+
+import com.cloud.dc.AccountVlanMapVO;
+import com.cloud.dc.PodVlanMapVO;
+import com.cloud.dc.Vlan;
+import com.cloud.dc.Vlan.VlanType;
+import com.cloud.dc.VlanVO;
+import com.cloud.network.dao.IPAddressDao;
+import com.cloud.utils.Pair;
+import com.cloud.utils.db.DB;
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.JoinBuilder;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@Component
+@Local(value={PortableIpDao.class})
+public class PortableIpDaoImpl extends GenericDaoBase<PortableIpVO, Long> implements PortableIpDao {
+
+    private final SearchBuilder<PortableIpVO> listByRegionIDSearch;
+    private final SearchBuilder<PortableIpVO> listByRangeIDSearch;
+    private final SearchBuilder<PortableIpVO> listByRangeIDAndStateSearch;
+    private final SearchBuilder<PortableIpVO> listByRegionIDAndStateSearch;
+    private final SearchBuilder<PortableIpVO> findByIpAddressSearch;
+
+    public PortableIpDaoImpl() {
+        listByRegionIDSearch = createSearchBuilder();
+        listByRegionIDSearch.and("regionId", listByRegionIDSearch.entity().getRegionId(), SearchCriteria.Op.EQ);
+        listByRegionIDSearch.done();
+
+        listByRangeIDSearch = createSearchBuilder();
+        listByRangeIDSearch.and("rangeId", listByRangeIDSearch.entity().getRangeId(), SearchCriteria.Op.EQ);
+        listByRangeIDSearch.done();
+
+        listByRangeIDAndStateSearch = createSearchBuilder();
+        listByRangeIDAndStateSearch.and("rangeId", listByRangeIDAndStateSearch.entity().getRangeId(), SearchCriteria.Op.EQ);
+        listByRangeIDAndStateSearch.and("state", listByRangeIDAndStateSearch.entity().getState(), SearchCriteria.Op.EQ);
+        listByRangeIDAndStateSearch.done();
+
+        listByRegionIDAndStateSearch = createSearchBuilder();
+        listByRegionIDAndStateSearch.and("regionId", listByRegionIDAndStateSearch.entity().getRangeId(), SearchCriteria.Op.EQ);
+        listByRegionIDAndStateSearch.and("state", listByRegionIDAndStateSearch.entity().getState(), SearchCriteria.Op.EQ);
+        listByRegionIDAndStateSearch.done();
+
+        findByIpAddressSearch = createSearchBuilder();
+        findByIpAddressSearch.and("address", findByIpAddressSearch.entity().getAddress(), SearchCriteria.Op.EQ);
+        findByIpAddressSearch.done();
+    }
+
+    @Override
+    public List<PortableIpVO> listByRegionId(int regionIdId) {
+        SearchCriteria<PortableIpVO> sc = listByRegionIDSearch.create();
+        sc.setParameters("regionId", regionIdId);
+        return listBy(sc);
+    }
+
+    @Override
+    public List<PortableIpVO> listByRangeId(long rangeId) {
+        SearchCriteria<PortableIpVO> sc = listByRangeIDSearch.create();
+        sc.setParameters("rangeId", rangeId);
+        return listBy(sc);
+    }
+
+    @Override
+    public List<PortableIpVO> listByRangeIdAndState(long rangeId, PortableIp.State state) {
+        SearchCriteria<PortableIpVO> sc = listByRangeIDAndStateSearch.create();
+        sc.setParameters("rangeId", rangeId);
+        sc.setParameters("state", state);
+        return listBy(sc);
+    }
+
+    @Override
+    public List<PortableIpVO> listByRegionIdAndState(int regionId, PortableIp.State state) {
+        SearchCriteria<PortableIpVO> sc = listByRegionIDAndStateSearch.create();
+        sc.setParameters("regionId", regionId);
+        sc.setParameters("state", state);
+        return listBy(sc);
+    }
+
+    @Override
+    public PortableIpVO findByIpAddress(String ipAddress) {
+        SearchCriteria<PortableIpVO> sc = findByIpAddressSearch.create();
+        sc.setParameters("address", ipAddress);
+        return findOneBy(sc);
+    }
+
+    @Override
+    public void unassignIpAddress(long ipAddressId) {
+        PortableIpVO address = createForUpdate();
+        address.setAllocatedToAccountId(null);
+        address.setAllocatedInDomainId(null);
+        address.setAllocatedTime(null);
+        address.setState(PortableIp.State.Free);
+        address.setAssociatedWithNetworkId(null);
+        address.setAssociatedDataCenterId(null);
+        address.setAssociatedWithVpcId(null);
+        address.setPhysicalNetworkId(null);
+        update(ipAddressId, address);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/server/src/org/apache/cloudstack/region/PortableIpRangeDao.java
----------------------------------------------------------------------
diff --git a/server/src/org/apache/cloudstack/region/PortableIpRangeDao.java b/server/src/org/apache/cloudstack/region/PortableIpRangeDao.java
new file mode 100755
index 0000000..85da6c0
--- /dev/null
+++ b/server/src/org/apache/cloudstack/region/PortableIpRangeDao.java
@@ -0,0 +1,30 @@
+// 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 org.apache.cloudstack.region;
+
+import java.util.List;
+
+import com.cloud.dc.Vlan;
+import com.cloud.dc.Vlan.VlanType;
+import com.cloud.dc.VlanVO;
+import com.cloud.utils.db.GenericDao;
+
+public interface PortableIpRangeDao extends GenericDao<PortableIpRangeVO, Long> {
+
+    List<PortableIpRangeVO> listByRegionId(int regionId);
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/server/src/org/apache/cloudstack/region/PortableIpRangeDaoImpl.java
----------------------------------------------------------------------
diff --git a/server/src/org/apache/cloudstack/region/PortableIpRangeDaoImpl.java b/server/src/org/apache/cloudstack/region/PortableIpRangeDaoImpl.java
new file mode 100755
index 0000000..496c9e6
--- /dev/null
+++ b/server/src/org/apache/cloudstack/region/PortableIpRangeDaoImpl.java
@@ -0,0 +1,65 @@
+// 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 org.apache.cloudstack.region;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.ejb.Local;
+import javax.inject.Inject;
+import javax.naming.ConfigurationException;
+
+import org.springframework.stereotype.Component;
+
+import com.cloud.dc.AccountVlanMapVO;
+import com.cloud.dc.PodVlanMapVO;
+import com.cloud.dc.Vlan;
+import com.cloud.dc.Vlan.VlanType;
+import com.cloud.dc.VlanVO;
+import com.cloud.network.dao.IPAddressDao;
+import com.cloud.utils.Pair;
+import com.cloud.utils.db.DB;
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.JoinBuilder;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@Component
+@Local(value={PortableIpRangeDao.class})
+public class PortableIpRangeDaoImpl extends GenericDaoBase<PortableIpRangeVO, Long> implements PortableIpRangeDao {
+
+    private final SearchBuilder<PortableIpRangeVO> listByRegionIDSearch;
+
+    public PortableIpRangeDaoImpl() {
+        listByRegionIDSearch = createSearchBuilder();
+        listByRegionIDSearch.and("regionId", listByRegionIDSearch.entity().getRegionId(), SearchCriteria.Op.EQ);
+        listByRegionIDSearch.done();
+    }
+
+    @Override
+    public List<PortableIpRangeVO> listByRegionId(int regionIdId) {
+        SearchCriteria<PortableIpRangeVO> sc = listByRegionIDSearch.create();
+        sc.setParameters("regionId", regionIdId);
+        return listBy(sc);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/server/src/org/apache/cloudstack/region/PortableIpRangeVO.java
----------------------------------------------------------------------
diff --git a/server/src/org/apache/cloudstack/region/PortableIpRangeVO.java b/server/src/org/apache/cloudstack/region/PortableIpRangeVO.java
new file mode 100644
index 0000000..933fcc3
--- /dev/null
+++ b/server/src/org/apache/cloudstack/region/PortableIpRangeVO.java
@@ -0,0 +1,119 @@
+// 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 org.apache.cloudstack.region;
+
+import java.util.UUID;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+import org.apache.cloudstack.api.Identity;
+import org.apache.cloudstack.api.InternalIdentity;
+
+@Entity
+@Table(name="portable_ip_range")
+public class PortableIpRangeVO implements PortableIpRange  {
+
+    @Id
+    @GeneratedValue(strategy=GenerationType.IDENTITY)
+    @Column(name="id")
+    Long id;
+
+    @Column(name="uuid")
+    String uuid;
+
+    @Column(name="region_id")
+    int regionId;
+
+    @Column(name="vlan_id")
+    String vlan;
+
+    @Column(name="gateway")
+    String gateway;
+
+    @Column(name="netmask")
+    String netmask;
+
+    @Column(name="start_ip")
+    String startIp;
+
+    @Column(name="end_ip")
+    String endIp;
+
+    public PortableIpRangeVO() {
+        this.uuid = UUID.randomUUID().toString();
+    }
+
+    public PortableIpRangeVO(int regionId, String vlan, String gateway, String netmask, String startIp, String endIp) {
+        this.uuid = UUID.randomUUID().toString();
+        this.regionId =regionId;
+        this.vlan = vlan;
+        this.gateway = gateway;
+        this.netmask = netmask;
+        this.startIp = startIp;
+        this.endIp = endIp;
+    }
+
+    @Override
+    public long getId() {
+        return id;
+    }
+
+    @Override
+    public String getUuid() {
+        return this.uuid;
+    }
+
+    public void setUuid(String uuid) {
+        this.uuid = uuid;
+    }
+
+    @Override
+    public String getVlanTag() {
+        return vlan;
+    }
+
+    public void setVlanTag(String vlan) {
+        this.vlan = vlan;
+    }
+
+    @Override
+    public String getGateway() {
+        return gateway;
+    }
+
+    @Override
+    public String getNetmask() {
+        return netmask;
+    }
+
+    @Override
+    public int getRegionId() {
+        return regionId;
+    }
+
+    @Override
+    public  String getIpRange() {
+        return startIp + "-" + endIp;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/server/src/org/apache/cloudstack/region/PortableIpVO.java
----------------------------------------------------------------------
diff --git a/server/src/org/apache/cloudstack/region/PortableIpVO.java b/server/src/org/apache/cloudstack/region/PortableIpVO.java
new file mode 100644
index 0000000..9a63009
--- /dev/null
+++ b/server/src/org/apache/cloudstack/region/PortableIpVO.java
@@ -0,0 +1,222 @@
+// 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 org.apache.cloudstack.region;
+
+import java.util.Date;
+import java.util.UUID;
+
+import javax.persistence.*;
+
+import org.apache.cloudstack.api.Identity;
+import org.apache.cloudstack.api.InternalIdentity;
+
+@Entity
+@Table(name="portable_ip_address")
+public class PortableIpVO  implements PortableIp  {
+
+    @Id
+    @GeneratedValue(strategy=GenerationType.IDENTITY)
+    @Column(name="id")
+    Long id;
+
+    @Column(name="region_id")
+    int regionId;
+
+    @Column(name="allocated")
+    @Temporal(value=TemporalType.TIMESTAMP)
+    private Date allocatedTime;
+
+    @Column(name="account_id")
+    private Long allocatedToAccountId = null;
+
+    @Column(name="domain_id")
+    private Long allocatedInDomainId = null;
+
+    @Column(name="state")
+    private State state;
+
+    @Column(name="vlan")
+    String vlan;
+
+    @Column(name="gateway")
+    String gateway;
+
+    @Column(name="netmask")
+    String netmask;
+
+    @Column(name="portable_ip_address")
+    String address;
+
+    @Column(name="portable_ip_range_id")
+    private long rangeId;
+
+    @Column(name="physical_network_id")
+    private Long physicalNetworkId;
+
+    @Column(name="data_center_id")
+    private Long dataCenterId;
+
+    @Column(name="network_id")
+    private Long networkId;
+
+    @Column(name="vpc_id")
+    private Long vpcId;
+
+    public PortableIpVO() {
+
+    }
+
+    public PortableIpVO(int regionId, Long rangeId, String vlan, String gateway, String netmask, String address) {
+        this.regionId =regionId;
+        this.vlan = vlan;
+        this.gateway = gateway;
+        this.netmask = netmask;
+        this.address = address;
+        state = State.Free;
+        this.rangeId = rangeId;
+    }
+
+    @Override
+    public long getId() {
+        return id;
+    }
+
+    @Override
+    public Long getAllocatedToAccountId() {
+        return allocatedToAccountId;
+    }
+
+    public void setAllocatedToAccountId(Long accountId) {
+        this.allocatedToAccountId = accountId;
+    }
+
+    @Override
+    public Long getAllocatedInDomainId() {
+        return allocatedInDomainId;
+    }
+
+    public void setAllocatedInDomainId(Long domainId) {
+        this.allocatedInDomainId = domainId;
+    }
+
+    @Override
+    public Date getAllocatedTime() {
+        return allocatedTime;
+    }
+
+    public void setAllocatedTime(Date date) {
+        this.allocatedTime = date;
+    }
+
+    @Override
+    public State getState() {
+        return state;
+    }
+
+    public void setState(State state) {
+        this.state = state;
+    }
+
+    @Override
+    public int getRegionId() {
+        return regionId;
+    }
+
+    public void setRegionId(int regionId) {
+        this.regionId = regionId;
+    }
+
+    @Override
+    public Long getAssociatedDataCenterId() {
+        return dataCenterId;
+    }
+
+    public void setAssociatedDataCenterId(Long datacenterId) {
+        this.dataCenterId = datacenterId;
+    }
+
+    @Override
+    public Long getAssociatedWithNetworkId() {
+        return networkId;
+    }
+
+    public void setAssociatedWithNetworkId(Long networkId) {
+        this.networkId =  networkId;
+    }
+
+    @Override
+    public Long getAssociatedWithVpcId() {
+        return vpcId;
+    }
+
+    public void setAssociatedWithVpcId(Long vpcId) {
+        this.vpcId =  vpcId;
+    }
+
+    @Override
+    public Long getPhysicalNetworkId() {
+        return physicalNetworkId;
+    }
+
+    public void setPhysicalNetworkId(Long physicalNetworkId) {
+        this.physicalNetworkId = physicalNetworkId;
+    }
+
+    @Override
+    public String getAddress() {
+        return address;
+    }
+
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    @Override
+    public String getVlan() {
+        return vlan;
+    }
+
+    public void setVlan(String vlan) {
+        this.vlan = vlan;
+    }
+
+    @Override
+    public String getNetmask() {
+        return netmask;
+    }
+
+    public void setNetmask(String netmask) {
+        this.netmask = netmask;
+    }
+
+    @Override
+    public String getGateway() {
+        return gateway;
+    }
+
+    public void setGateay(String gateway) {
+        this.gateway = gateway;
+    }
+
+    Long getRangeId() {
+        return rangeId;
+    }
+
+    public void setRangeId(Long rangeId) {
+        this.rangeId = rangeId;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/server/test/com/cloud/network/MockNetworkManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/network/MockNetworkManagerImpl.java b/server/test/com/cloud/network/MockNetworkManagerImpl.java
index 87431ab..1ac014d 100755
--- a/server/test/com/cloud/network/MockNetworkManagerImpl.java
+++ b/server/test/com/cloud/network/MockNetworkManagerImpl.java
@@ -75,7 +75,6 @@ import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.*;
 import com.cloud.vm.VirtualMachine.Type;
 import com.cloud.vm.VirtualMachineProfile;
-import org.apache.cloudstack.acl.ControlledEntity.ACLType;
 import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd;
 import org.apache.cloudstack.api.command.admin.network.ListDedicatedGuestVlanRangesCmd;
 import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd;
@@ -89,7 +88,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-
 @Component
 @Local(value = { NetworkManager.class, NetworkService.class })
 public class MockNetworkManagerImpl extends ManagerBase implements NetworkManager, NetworkService {
@@ -107,6 +105,27 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage
     }
 
     @Override
+    public IPAddressVO associatePortableIPToGuestNetwork(long ipAddrId, long networkId, boolean releaseOnFailure) throws ResourceAllocationException, ResourceUnavailableException {
+        return null;// TODO Auto-generated method stub
+    }
+
+    @Override
+    public IPAddressVO disassociatePortableIPToGuestNetwork(long ipAddrId, long networkId) throws ResourceAllocationException, ResourceUnavailableException, InsufficientAddressCapacityException, ConcurrentOperationException {
+        return null;  // TODO Auto-generated method stub
+    }
+
+    @Override
+    public boolean isPortableIpTransferableFromNetwork(long ipAddrId, long networkId) {
+        return false;
+    }
+
+    @Override
+    public void transferPortableIP(long ipAddrId, long currentNetworkId, long newNetworkId)  throws ResourceAllocationException, ResourceUnavailableException,
+            InsufficientAddressCapacityException, ConcurrentOperationException {
+
+    }
+
+    @Override
     public boolean releaseIpAddress(long ipAddressId) {
         // TODO Auto-generated method stub
         return false;
@@ -862,6 +881,23 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage
     }
 
     @Override
+    public IpAddress allocatePortableIp(Account ipOwner, Account caller, long dcId, Long networkId, Long vpcID)
+            throws ConcurrentOperationException, ResourceAllocationException, InsufficientAddressCapacityException {
+        return null;// TODO Auto-generated method stub
+    }
+
+    @Override
+    public IpAddress allocatePortableIP(Account ipOwner, int regionId, Long zoneId, Long networkId, Long vpcId) throws ResourceAllocationException,
+            InsufficientAddressCapacityException, ConcurrentOperationException {
+        return null;
+    }
+
+    @Override
+    public boolean releasePortableIpAddress(long ipAddressId) throws InsufficientAddressCapacityException {
+        return false;// TODO Auto-generated method stub
+    }
+
+    @Override
     public boolean isSecondaryIpSetForNic(long nicId) {
         // TODO Auto-generated method stub
         return false;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
index 4fb182a..21b3590 100755
--- a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
+++ b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
@@ -16,6 +16,44 @@
 // under the License.
 package com.cloud.vpc;
 
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.ejb.Local;
+import javax.inject.Inject;
+import javax.naming.ConfigurationException;
+import javax.naming.NamingException;
+
+import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd;
+import org.apache.cloudstack.api.command.admin.ldap.LDAPConfigCmd;
+import org.apache.cloudstack.api.command.admin.ldap.LDAPRemoveCmd;
+import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd;
+import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd;
+import org.apache.cloudstack.api.command.admin.network.UpdateNetworkOfferingCmd;
+import org.apache.cloudstack.api.command.admin.offering.CreateDiskOfferingCmd;
+import org.apache.cloudstack.api.command.admin.offering.CreateServiceOfferingCmd;
+import org.apache.cloudstack.api.command.admin.offering.DeleteDiskOfferingCmd;
+import org.apache.cloudstack.api.command.admin.offering.DeleteServiceOfferingCmd;
+import org.apache.cloudstack.api.command.admin.offering.UpdateDiskOfferingCmd;
+import org.apache.cloudstack.api.command.admin.offering.UpdateServiceOfferingCmd;
+import org.apache.cloudstack.api.command.admin.pod.DeletePodCmd;
+import org.apache.cloudstack.api.command.admin.pod.UpdatePodCmd;
+import org.apache.cloudstack.api.command.admin.region.CreatePortableIpRangeCmd;
+import org.apache.cloudstack.api.command.admin.region.DeletePortableIpRangeCmd;
+import org.apache.cloudstack.api.command.admin.region.ListPortableIpRangesCmd;
+import org.apache.cloudstack.api.command.admin.vlan.CreateVlanIpRangeCmd;
+import org.apache.cloudstack.api.command.admin.vlan.DedicatePublicIpRangeCmd;
+import org.apache.cloudstack.api.command.admin.vlan.DeleteVlanIpRangeCmd;
+import org.apache.cloudstack.api.command.admin.vlan.ReleasePublicIpRangeCmd;
+import org.apache.cloudstack.api.command.admin.zone.CreateZoneCmd;
+import org.apache.cloudstack.api.command.admin.zone.DeleteZoneCmd;
+import org.apache.cloudstack.api.command.admin.zone.UpdateZoneCmd;
+import org.apache.cloudstack.api.command.user.network.ListNetworkOfferingsCmd;
+import org.apache.cloudstack.region.PortableIp;
+import org.apache.cloudstack.region.PortableIpRange;
+import org.springframework.stereotype.Component;
+
 import com.cloud.configuration.Configuration;
 import com.cloud.configuration.ConfigurationManager;
 import com.cloud.configuration.ConfigurationService;
@@ -381,6 +419,26 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu
         return false;
     }
 
+    @Override
+    public PortableIpRange createPortableIpRange(CreatePortableIpRangeCmd cmd) throws ConcurrentOperationException {
+        return null;// TODO Auto-generated method stub
+    }
+
+    @Override
+    public boolean deletePortableIpRange(DeletePortableIpRangeCmd cmd) {
+        return false;// TODO Auto-generated method stub
+    }
+
+    @Override
+    public List<? extends PortableIpRange> listPortableIpRanges(ListPortableIpRangesCmd cmd) {
+        return null;// TODO Auto-generated method stub
+    }
+
+    @Override
+    public List<? extends PortableIp> listPortableIps(long id) {
+        return null;// TODO Auto-generated method stub
+    }
+
     /* (non-Javadoc)
      * @see com.cloud.utils.component.Manager#configure(java.lang.String, java.util.Map)
      */

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/server/test/com/cloud/vpc/MockNetworkManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java
index 3e6a08b..62599b8 100644
--- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java
+++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java
@@ -63,7 +63,6 @@ import com.cloud.network.PhysicalNetworkServiceProvider;
 import com.cloud.network.PhysicalNetworkTrafficType;
 import com.cloud.network.PublicIpAddress;
 import com.cloud.network.addr.PublicIp;
-import com.cloud.network.dao.AccountGuestVlanMapVO;
 import com.cloud.network.dao.IPAddressVO;
 import com.cloud.network.dao.NetworkServiceMapDao;
 import com.cloud.network.dao.NetworkVO;
@@ -198,13 +197,36 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage
         return null;
     }
 
+    @Override
+    public IpAddress allocatePortableIp(Account ipOwner, Account caller, long dcId, Long networkId, Long vpcID)
+            throws ConcurrentOperationException, ResourceAllocationException, InsufficientAddressCapacityException {
+        return null;// TODO Auto-generated method stub
+    }
 
+    @Override
+    public IpAddress allocatePortableIP(Account ipOwner, int regionId, Long zoneId, Long networkId, Long vpcId) throws ResourceAllocationException,
+            InsufficientAddressCapacityException, ConcurrentOperationException {
+        return null;
+    }
 
+    @Override
+    public boolean releasePortableIpAddress(long ipAddressId) throws InsufficientAddressCapacityException {
+        return false;// TODO Auto-generated method stub
+    }
 
+    @Override
+    public boolean isPortableIpTransferableFromNetwork(long ipAddrId, long networkId) {
+        return false;
+    }
+
+    @Override
+    public void transferPortableIP(long ipAddrId, long currentNetworkId, long newNetworkId)  throws ResourceAllocationException, ResourceUnavailableException,
+            InsufficientAddressCapacityException, ConcurrentOperationException {
+    }
 
     /* (non-Javadoc)
-     * @see com.cloud.network.NetworkService#releaseIpAddress(long)
-     */
+    * @see com.cloud.network.NetworkService#releaseIpAddress(long)
+    */
     @Override
     public boolean releaseIpAddress(long ipAddressId) throws InsufficientAddressCapacityException {
         // TODO Auto-generated method stub
@@ -1112,13 +1134,20 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage
         return null;
     }
 
+    @Override
+    public IPAddressVO associatePortableIPToGuestNetwork(long ipAddrId, long networkId, boolean releaseOnFailure) throws ResourceAllocationException, ResourceUnavailableException {
+        return null;// TODO Auto-generated method stub
+    }
 
-
+    @Override
+    public IPAddressVO disassociatePortableIPToGuestNetwork(long ipAddrId, long networkId) throws ResourceAllocationException, ResourceUnavailableException, InsufficientAddressCapacityException, ConcurrentOperationException {
+        return null;// TODO Auto-generated method stub
+    }
 
 
     /* (non-Javadoc)
-     * @see com.cloud.network.NetworkManager#setupDns(com.cloud.network.Network, com.cloud.network.Network.Provider)
-     */
+    * @see com.cloud.network.NetworkManager#setupDns(com.cloud.network.Network, com.cloud.network.Network.Provider)
+    */
     @Override
     public boolean setupDns(Network network, Provider provider) {
         // TODO Auto-generated method stub

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java
----------------------------------------------------------------------
diff --git a/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java b/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java
index a825699..f862a2a 100644
--- a/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java
+++ b/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java
@@ -20,6 +20,9 @@ package org.apache.cloudstack.networkoffering;
 import java.io.IOException;
 
 import org.apache.cloudstack.acl.SecurityChecker;
+import org.apache.cloudstack.region.PortableIpDaoImpl;
+import org.apache.cloudstack.region.dao.RegionDaoImpl;
+import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDaoImpl;
 import org.apache.cloudstack.test.utils.SpringUtils;
 import org.mockito.Mockito;
@@ -113,6 +116,7 @@ import com.cloud.vm.dao.NicDaoImpl;
 import com.cloud.vm.dao.NicSecondaryIpDaoImpl;
 import com.cloud.vm.dao.UserVmDao;
 import com.cloud.vm.dao.VMInstanceDaoImpl;
+import org.apache.cloudstack.region.PortableIpRangeDaoImpl;
 
 @Configuration
 @ComponentScan(basePackageClasses={
@@ -162,6 +166,9 @@ import com.cloud.vm.dao.VMInstanceDaoImpl;
         NetworkServiceMapDaoImpl.class,
         PrimaryDataStoreDaoImpl.class,
         StoragePoolDetailsDaoImpl.class,
+        PortableIpRangeDaoImpl.class,
+        RegionDaoImpl.class,
+        PortableIpDaoImpl.class,
         AccountGuestVlanMapDaoImpl.class
     },
 includeFilters={@Filter(value=ChildTestConfiguration.Library.class, type=FilterType.CUSTOM)},

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/setup/db/db/schema-410to420.sql
----------------------------------------------------------------------
diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql
index c088ac1..7b5e9cb 100644
--- a/setup/db/db/schema-410to420.sql
+++ b/setup/db/db/schema-410to420.sql
@@ -1267,6 +1267,43 @@ INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'Netwo
 
 
 alter table `cloud_usage`.`usage_network_offering` add column nic_id bigint(20) unsigned NOT NULL;
+
+CREATE TABLE `cloud`.`portable_ip_range` (
+  `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT,
+  `uuid` varchar(40),
+  `region_id` int unsigned NOT NULL,
+  `vlan_id` varchar(255),
+  `gateway` varchar(255),
+  `netmask` varchar(255),
+  `start_ip` varchar(255),
+  `end_ip` varchar(255),
+  PRIMARY KEY (`id`),
+  CONSTRAINT `fk_portableip__region_id` FOREIGN KEY (`region_id`) REFERENCES `region`(`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE `cloud`.`portable_ip_address` (
+  `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT,
+  `account_id` bigint unsigned NULL,
+  `domain_id` bigint unsigned NULL,
+  `allocated` datetime NULL COMMENT 'Date portable ip was allocated',
+  `state` char(32) NOT NULL default 'Free' COMMENT 'state of the portable ip address',
+  `region_id` int unsigned NOT NULL,
+  `vlan` varchar(255),
+  `gateway` varchar(255),
+  `netmask` varchar(255),
+  `portable_ip_address` varchar(255),
+  `portable_ip_range_id` bigint unsigned NOT NULL,
+  `data_center_id` bigint unsigned NULL COMMENT 'zone to which portable IP is associated',
+  `physical_network_id` bigint unsigned NULL COMMENT 'physical network id in the zone to which portable IP is associated',
+  `network_id` bigint unsigned NULL COMMENT 'guest network to which portable ip address is associated with',
+  `vpc_id` bigint unsigned COMMENT 'vpc to which portable ip address is associated with',
+  PRIMARY KEY (`id`),
+  CONSTRAINT `fk_portable_ip_address__portable_ip_range_id` FOREIGN KEY (`portable_ip_range_id`) REFERENCES `portable_ip_range`(`id`) ON DELETE CASCADE,
+  CONSTRAINT `fk_portable_ip_address__region_id` FOREIGN KEY (`region_id`) REFERENCES `region`(`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+ALTER TABLE `cloud`.`user_ip_address` ADD COLUMN is_portable int(1) unsigned NOT NULL default '0';
+
 DROP VIEW IF EXISTS `cloud`.`disk_offering_view`;
 CREATE VIEW `cloud`.`disk_offering_view` AS
     select

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/test/integration/smoke/test_portable_publicip.py
----------------------------------------------------------------------
diff --git a/test/integration/smoke/test_portable_publicip.py b/test/integration/smoke/test_portable_publicip.py
new file mode 100644
index 0000000..101747d
--- /dev/null
+++ b/test/integration/smoke/test_portable_publicip.py
@@ -0,0 +1,237 @@
+#!/usr/bin/env python
+# 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.
+
+from marvin.cloudstackTestCase import *
+from marvin.cloudstackAPI import *
+from marvin.integration.lib.utils import *
+from marvin.integration.lib.base import *
+from marvin.integration.lib.common import *
+from marvin import remoteSSHClient
+from nose.plugins.attrib import attr
+
+class Services:
+    """Test Data
+    """
+
+    def __init__(self):
+        self.services = {
+            "domain": {
+                "name": "Domain",
+            },
+            "account": {
+                "email": "test@test.com",
+                "firstname": "Test",
+                "lastname": "User",
+                "username": "test",
+                # Random characters are appended for unique
+                # username
+                "password": "password",
+            },
+            "service_offering": {
+                "name": "Tiny Instance",
+                "displaytext": "Tiny Instance",
+                "cpunumber": 1,
+                "cpuspeed": 100,
+                # in MHz
+                "memory": 128,
+                # In MBs
+            },
+            "network_offering": {
+                    "name": 'Test Network offering',
+                    "displaytext": 'Test Network offering',
+                    "guestiptype": 'Isolated',
+                    "supportedservices": 'Dhcp,Dns,SourceNat,PortForwarding',
+                    "traffictype": 'GUEST',
+                    "availability": 'Optional',
+                    "serviceProviderList" : {
+                            "Dhcp": 'VirtualRouter',
+                            "Dns": 'VirtualRouter',
+                            "SourceNat": 'VirtualRouter',
+                            "PortForwarding": 'VirtualRouter',
+                        },
+            },
+            "network": {
+                "name": "Test Network",
+                "displaytext": "Test Network",
+            },
+            "ostype": 'CentOS 5.3 (64-bit)',
+            "gateway" : "10.1.1.1",
+            "netmask" : "255.255.255.0",
+            "startip" : "10.1.1.10",
+            "endip" : "10.1.1.20",
+            "regionid" : "1",
+            "vlan" :"10",
+            "isportable" : "true",
+            "virtual_machine" : {
+                "affinity": {
+                    "name": "webvms",
+                    "type": "host anti-affinity",
+                },
+                "hypervisor" : "XenServer",
+            }
+        }
+
+class TestPortablePublicIPRange(cloudstackTestCase):
+
+    """
+    This test validates functionality where
+      - admin can provision a portable public ip range
+      - list provisioned portable public ip range
+      - delete provisioned portable public ip range
+    """
+    @classmethod
+    def setUpClass(cls):
+        cls.api_client = super(TestPortablePublicIPRange, cls).getClsTestClient().getApiClient()
+        cls.services = Services().services
+        # Get Zone, Domain
+        cls.domain = get_domain(cls.api_client, cls.services)
+        cls.zone = get_zone(cls.api_client, cls.services)
+
+        # Create Account
+        cls.account = Account.create(
+                            cls.api_client,
+                            cls.services["account"],
+                            domainid=cls.domain.id
+                            )
+        cls._cleanup = [
+                        cls.account,
+                        ]
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        try:
+            # Cleanup resources used
+            cleanup_resources(cls.api_client, cls._cleanup)
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def setUp(self):
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            # Clean up
+            cleanup_resources(self.apiclient, self.cleanup)
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    @attr(tags = ["simulator", "basic", "advanced",  "portablepublicip"])
+    def test_createPortablePublicIPRange(self):
+        """
+        """
+        self.debug("attempting to create a portable Public IP range")
+        self.portable_ip_range = PortablePublicIpRange.create(
+                                    self.api_client,
+                                    self.services
+                               )
+        self.debug("attempting to verify portable Public IP range is created")
+        list_portbale_ip_range_response = PortablePublicIpRange.list(
+                                            self.apiclient,
+                                            id=self.portable_ip_range.id
+                                        )
+        self.portable_ip_range.delete(self.apiclient)
+        return
+
+
+class TestPortablePublicIPAcquire(cloudstackTestCase):
+
+    """
+    This test validates functionality where
+      - admin has provisioned a portable public ip range
+      - user can acquire portable ip from the provisioned ip range
+    """
+    @classmethod
+    def setUpClass(cls):
+        cls.api_client = super(TestPortablePublicIPAcquire, cls).getClsTestClient().getApiClient()
+        cls.services = Services().services
+        # Get Zone, Domain
+        cls.domain = get_domain(cls.api_client, cls.services)
+        cls.zone = get_zone(cls.api_client, cls.services)
+        # Create Account
+        cls.account = Account.create(
+                            cls.api_client,
+                            cls.services["account"],
+                            domainid=cls.domain.id
+                            )
+        cls.services["network"]["zoneid"] = cls.zone.id
+
+        cls.network_offering = NetworkOffering.create(
+                                    cls.api_client,
+                                    cls.services["network_offering"],
+                                    )
+        # Enable Network offering
+        cls.network_offering.update(cls.api_client, state='Enabled')
+
+        cls.services["network"]["networkoffering"] = cls.network_offering.id
+        cls.account_network = Network.create(
+                                             cls.api_client,
+                                             cls.services["network"],
+                                             cls.account.name,
+                                             cls.account.domainid
+                                             )
+        cls._cleanup = [
+                        cls.account_network,
+                        cls.network_offering,
+                        cls.account
+                       ]
+
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        try:
+            # Cleanup resources used
+            cleanup_resources(cls.api_client, cls._cleanup)
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    def setUp(self):
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        try:
+            # Clean up
+            cleanup_resources(self.apiclient, self.cleanup)
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    @attr(tags = ["simulator", "basic", "advanced",  "portablepublicip"])
+    def test_createPortablePublicIPAcquire(self):
+        """
+        """
+        self.debug("attempting to create a portable Public IP range")
+        self.portable_ip_range = PortablePublicIpRange.create(
+                                    self.api_client,
+                                    self.services
+                                    )
+
+        ip_address = PublicIPAddress.create(self.api_client, self.account.name, self.zone.id, self.account.domainid)
+
+        self.portable_ip_range.delete(self.apiclient)
+        return
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/tools/marvin/marvin/integration/lib/base.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base.py b/tools/marvin/marvin/integration/lib/base.py
index f3a96bd..ec1c34e 100755
--- a/tools/marvin/marvin/integration/lib/base.py
+++ b/tools/marvin/marvin/integration/lib/base.py
@@ -2131,6 +2131,42 @@ class PublicIpRange:
         cmd.id = self.vlan.id
         return apiclient.releasePublicIpRange(cmd)
 
+
+class PortablePublicIpRange:
+    """Manage portable public Ip Range"""
+
+    def __init__(self, items):
+        self.__dict__.update(items)
+
+    @classmethod
+    def create(cls, apiclient, services):
+        """Create portable public Ip Range"""
+
+        cmd = createPortableIpRange.createPortableIpRangeCmd()
+        cmd.gateway = services["gateway"]
+        cmd.netmask = services["netmask"]
+        cmd.startip = services["startip"]
+        cmd.endip = services["endip"]
+        cmd.regionid = services["regionid"]
+        cmd.vlan = services["vlan"]
+
+        return PortablePublicIpRange(apiclient.createVlanIpRange(cmd).__dict__)
+
+    def delete(self, apiclient):
+        """Delete portable IpRange"""
+
+        cmd = deletePortableIpRange.deletePortableIpRangeCmd()
+        cmd.id = self.id
+        apiclient.deletePortableIpRange(cmd)
+
+    @classmethod
+    def list(cls, apiclient, **kwargs):
+        """Lists all portable public IP ranges."""
+
+        cmd = listPortableIpRanges.listPortableIpRangesCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        return(apiclient.listPortableIpRanges(cmd))
+
 class SecondaryStorage:
     """Manage Secondary storage"""
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/utils/src/com/cloud/utils/net/NetUtils.java
----------------------------------------------------------------------
diff --git a/utils/src/com/cloud/utils/net/NetUtils.java b/utils/src/com/cloud/utils/net/NetUtils.java
index 9551c26..37dcef3 100755
--- a/utils/src/com/cloud/utils/net/NetUtils.java
+++ b/utils/src/com/cloud/utils/net/NetUtils.java
@@ -1296,6 +1296,18 @@ public class NetUtils {
 		return resultIp;
 	}
 
+    public static boolean isValidVlan(String vlan) {
+        try {
+            int vnet = Integer.parseInt(vlan);
+            if (vnet < 0 || vnet > 4096) {
+                return false;
+            }
+            return true;
+        } catch (NumberFormatException e) {
+            return false;
+        }
+    }
+
 	public static URI generateUriForPvlan(String primaryVlan, String isolatedPvlan) {
         return URI.create("pvlan://" + primaryVlan + "-i" + isolatedPvlan);
 	}
@@ -1320,4 +1332,5 @@ public class NetUtils {
 		}
 		return null;
 	}
+
 }


Mime
View raw message