cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bfede...@apache.org
Subject [02/50] [abbrv] git commit: updated refs/heads/ui-new-project-switcher to a748988
Date Tue, 16 Apr 2013 18:03:35 GMT
Dedicate Public IP address range to an account


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/8f865c5a
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/8f865c5a
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/8f865c5a

Branch: refs/heads/ui-new-project-switcher
Commit: 8f865c5a901d1fb066709e1809fd5538af3eea11
Parents: 95cbb79
Author: Likitha Shetty <likitha.shetty@citrix.com>
Authored: Mon Apr 8 22:44:45 2013 +0530
Committer: Likitha Shetty <likitha.shetty@citrix.com>
Committed: Fri Apr 12 23:27:35 2013 +0530

----------------------------------------------------------------------
 .../cloud/configuration/ConfigurationService.java  |    6 +
 api/src/com/cloud/event/EventTypes.java            |    4 +
 .../admin/vlan/DedicatePublicIpRangeCmd.java       |  108 ++++
 .../admin/vlan/ReleasePublicIpRangeCmd.java        |   77 +++
 client/tomcatconf/commands.properties.in           |    2 +
 .../cloud/configuration/ConfigurationManager.java  |    5 +-
 .../configuration/ConfigurationManagerImpl.java    |  173 ++++++-
 .../src/com/cloud/network/NetworkManagerImpl.java  |   45 ++-
 .../src/com/cloud/network/NetworkServiceImpl.java  |    9 -
 .../src/com/cloud/server/ManagementServerImpl.java |    3 +
 server/src/com/cloud/user/AccountManagerImpl.java  |    6 +-
 .../configuration/ConfigurationManagerTest.java    |  413 +++++++++++++++
 .../cloud/vpc/MockConfigurationManagerImpl.java    |   23 +-
 test/integration/component/test_public_ip_range.py |  173 ++++++
 tools/marvin/marvin/integration/lib/base.py        |   19 +-
 15 files changed, 1017 insertions(+), 49 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f865c5a/api/src/com/cloud/configuration/ConfigurationService.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/configuration/ConfigurationService.java b/api/src/com/cloud/configuration/ConfigurationService.java
index e63fcec..6937d0b 100644
--- a/api/src/com/cloud/configuration/ConfigurationService.java
+++ b/api/src/com/cloud/configuration/ConfigurationService.java
@@ -35,7 +35,9 @@ 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.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;
@@ -234,6 +236,10 @@ public interface ConfigurationService {
 
     boolean deleteVlanIpRange(DeleteVlanIpRangeCmd cmd);
 
+    Vlan dedicatePublicIpRange(DedicatePublicIpRangeCmd cmd) throws ResourceAllocationException;
+
+    boolean releasePublicIpRange(ReleasePublicIpRangeCmd cmd);
+
     NetworkOffering createNetworkOffering(CreateNetworkOfferingCmd cmd);
 
     NetworkOffering updateNetworkOffering(UpdateNetworkOfferingCmd cmd);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f865c5a/api/src/com/cloud/event/EventTypes.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java
index 6a26212..0ee7f40 100755
--- a/api/src/com/cloud/event/EventTypes.java
+++ b/api/src/com/cloud/event/EventTypes.java
@@ -226,6 +226,8 @@ public class EventTypes {
     // VLANs/IP ranges
     public static final String EVENT_VLAN_IP_RANGE_CREATE = "VLAN.IP.RANGE.CREATE";
     public static final String EVENT_VLAN_IP_RANGE_DELETE = "VLAN.IP.RANGE.DELETE";
+    public static final String EVENT_VLAN_IP_RANGE_DEDICATE = "VLAN.IP.RANGE.DEDICATE";
+    public static final String EVENT_VLAN_IP_RANGE_RELEASE = "VLAN.IP.RANGE.RELEASE";
 
     public static final String EVENT_STORAGE_IP_RANGE_CREATE = "STORAGE.IP.RANGE.CREATE";
     public static final String EVENT_STORAGE_IP_RANGE_DELETE = "STORAGE.IP.RANGE.DELETE";
@@ -545,6 +547,8 @@ public class EventTypes {
         // VLANs/IP ranges
         entityEventDetails.put(EVENT_VLAN_IP_RANGE_CREATE, Vlan.class.getName());
         entityEventDetails.put(EVENT_VLAN_IP_RANGE_DELETE,Vlan.class.getName());
+        entityEventDetails.put(EVENT_VLAN_IP_RANGE_DEDICATE, Vlan.class.getName());
+        entityEventDetails.put(EVENT_VLAN_IP_RANGE_RELEASE,Vlan.class.getName());
 
         entityEventDetails.put(EVENT_STORAGE_IP_RANGE_CREATE, StorageNetworkIpRange.class.getName());
         entityEventDetails.put(EVENT_STORAGE_IP_RANGE_DELETE, StorageNetworkIpRange.class.getName());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f865c5a/api/src/org/apache/cloudstack/api/command/admin/vlan/DedicatePublicIpRangeCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/vlan/DedicatePublicIpRangeCmd.java b/api/src/org/apache/cloudstack/api/command/admin/vlan/DedicatePublicIpRangeCmd.java
new file mode 100755
index 0000000..e7b1105
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/vlan/DedicatePublicIpRangeCmd.java
@@ -0,0 +1,108 @@
+// 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.api.command.admin.vlan;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.DomainResponse;
+import org.apache.cloudstack.api.response.ProjectResponse;
+import org.apache.cloudstack.api.response.VlanIpRangeResponse;
+import org.apache.cloudstack.api.response.ZoneResponse;
+import org.apache.log4j.Logger;
+
+import com.cloud.dc.Vlan;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.user.Account;
+
+@APICommand(name = "dedicatePublicIpRange", description="Dedicates a Public IP range to an account", responseObject=VlanIpRangeResponse.class)
+public class DedicatePublicIpRangeCmd extends BaseCmd {
+    public static final Logger s_logger = Logger.getLogger(DedicatePublicIpRangeCmd.class.getName());
+
+    private static final String s_name = "dedicatepubliciprangeresponse";
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType = VlanIpRangeResponse.class,
+            required=true, description="the id of the VLAN IP range")
+    private Long id;
+
+    @Parameter(name=ApiConstants.ACCOUNT, type=CommandType.STRING, required=true,
+            description="account who will own the VLAN")
+    private String accountName;
+
+    @Parameter(name=ApiConstants.PROJECT_ID, type=CommandType.UUID, entityType = ProjectResponse.class,
+            description="project who will own the VLAN")
+    private Long projectId;
+
+    @Parameter(name=ApiConstants.DOMAIN_ID, type=CommandType.UUID, entityType = DomainResponse.class,
+            required=true, description="domain ID of the account owning a VLAN")
+    private Long domainId;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getId() {
+        return id;
+    }
+
+    public String getAccountName() {
+        return accountName;
+    }
+
+    public Long getDomainId() {
+        return domainId;
+    }
+
+    public Long getProjectId() {
+        return projectId;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return Account.ACCOUNT_ID_SYSTEM;
+    }
+
+    @Override
+    public void execute() throws ResourceUnavailableException, ResourceAllocationException {
+        Vlan result = _configService.dedicatePublicIpRange(this);
+        if (result != null) {
+            VlanIpRangeResponse response = _responseGenerator.createVlanIpRangeResponse(result);
+            response.setResponseName(getCommandName());
+            this.setResponseObject(response);
+        } else {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to dedicate vlan ip range");
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f865c5a/api/src/org/apache/cloudstack/api/command/admin/vlan/ReleasePublicIpRangeCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/vlan/ReleasePublicIpRangeCmd.java b/api/src/org/apache/cloudstack/api/command/admin/vlan/ReleasePublicIpRangeCmd.java
new file mode 100644
index 0000000..91cc7d3
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/vlan/ReleasePublicIpRangeCmd.java
@@ -0,0 +1,77 @@
+// 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.api.command.admin.vlan;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import org.apache.cloudstack.api.response.VlanIpRangeResponse;
+import org.apache.log4j.Logger;
+
+import com.cloud.user.Account;
+
+@APICommand(name = "releasePublicIpRange", description="Releases a Public IP range back to the system pool", responseObject=SuccessResponse.class)
+public class ReleasePublicIpRangeCmd extends BaseCmd {
+    public static final Logger s_logger = Logger.getLogger(ReleasePublicIpRangeCmd.class.getName());
+
+    private static final String s_name = "releasepubliciprangeresponse";
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType = VlanIpRangeResponse.class,
+            required=true, description="the id of the Public IP range")
+    private Long id;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getId() {
+        return id;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return Account.ACCOUNT_ID_SYSTEM;
+    }
+
+    @Override
+    public void execute(){
+        boolean result = _configService.releasePublicIpRange(this);
+        if (result) {
+            SuccessResponse response = new SuccessResponse(getCommandName());
+            this.setResponseObject(response);
+        } else {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to release public ip range");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f865c5a/client/tomcatconf/commands.properties.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in
index 4ce9fd3..798d226 100644
--- a/client/tomcatconf/commands.properties.in
+++ b/client/tomcatconf/commands.properties.in
@@ -124,6 +124,8 @@ listDiskOfferings=15
 createVlanIpRange=1
 deleteVlanIpRange=1
 listVlanIpRanges=1
+dedicatePublicIpRange=1
+releasePublicIpRange=1
 
 #### address commands
 associateIpAddress=15

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f865c5a/server/src/com/cloud/configuration/ConfigurationManager.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/ConfigurationManager.java b/server/src/com/cloud/configuration/ConfigurationManager.java
old mode 100644
new mode 100755
index c5f65e9..d7faf19
--- a/server/src/com/cloud/configuration/ConfigurationManager.java
+++ b/server/src/com/cloud/configuration/ConfigurationManager.java
@@ -30,6 +30,7 @@ import com.cloud.dc.Vlan;
 import com.cloud.exception.ConcurrentOperationException;
 import com.cloud.exception.InsufficientCapacityException;
 import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.ResourceAllocationException;
 import com.cloud.network.Network;
 import com.cloud.network.Network.Capability;
 import com.cloud.network.Network.Provider;
@@ -150,6 +151,8 @@ public interface ConfigurationManager extends ConfigurationService, Manager {
      */
     boolean deleteVlanAndPublicIpRange(long userId, long vlanDbId, Account caller);
 
+    boolean releasePublicIpRange(long userId, long vlanDbId, Account caller);
+
     /**
      * Converts a comma separated list of tags to a List
      * 
@@ -211,7 +214,7 @@ public interface ConfigurationManager extends ConfigurationService, Manager {
 
     ClusterVO getCluster(long id);
 
-    boolean deleteAccountSpecificVirtualRanges(long accountId);
+    boolean releaseAccountSpecificVirtualRanges(long accountId);
 
     /**
      * Edits a pod in the database. Will not allow you to edit pods that are being used anywhere in the system.

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f865c5a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
index ceeae1e..fce3c01 100755
--- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -56,7 +56,9 @@ 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.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;
@@ -2306,9 +2308,6 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
             throw new InvalidParameterValueException("Gateway, netmask and zoneId have to be passed in for virtual and direct untagged networks");
         }
 
-        // if it's an account specific range, associate ip address list to the account
-        boolean associateIpRangeToAccount = false;
-
         if (forVirtualNetwork) {
             if (vlanOwner != null) {
 
@@ -2316,8 +2315,6 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
 
                 //check resource limits
                 _resourceLimitMgr.checkResourceLimit(vlanOwner, ResourceType.public_ip, accountIpRange);
-                
-                associateIpRangeToAccount = true;
             }
         }
 
@@ -2332,21 +2329,6 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
                 endIP, vlanGateway, vlanNetmask, vlanId, vlanOwner, startIPv6, endIPv6, ip6Gateway, ip6Cidr);
 
         txn.commit();
-        if (associateIpRangeToAccount) {
-            _networkMgr.associateIpAddressListToAccount(userId, vlanOwner.getId(), zoneId, vlan.getId(), null);
-        }
-
-        // Associate ips to the network
-        if (associateIpRangeToAccount) {
-            if (network.getState() == Network.State.Implemented) {
-                s_logger.debug("Applying ip associations for vlan id=" + vlanId + " in network " + network);
-                if (!_networkMgr.applyIpAssociations(network, false)) {
-                    s_logger.warn("Failed to apply ip associations for vlan id=1 as a part of add vlan range for account id=" + vlanOwner.getId());
-                }
-            } else {
-                s_logger.trace("Network id=" + network.getId() + " is not Implemented, no need to apply ipAssociations");
-            }
-        }
 
         return vlan;
     }
@@ -2699,6 +2681,149 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
     }
 
     @Override
+    @DB
+    @ActionEvent(eventType = EventTypes.EVENT_VLAN_IP_RANGE_DEDICATE, eventDescription = "dedicating vlan ip range", async = false)
+    public Vlan dedicatePublicIpRange(DedicatePublicIpRangeCmd cmd) throws ResourceAllocationException {
+        Long vlanDbId = cmd.getId();
+        String accountName = cmd.getAccountName();
+        Long domainId = cmd.getDomainId();
+        Long projectId = cmd.getProjectId();
+
+        // Check if account is valid
+        Account vlanOwner = null;
+        if (projectId != null) {
+            if (accountName != null) {
+                throw new InvalidParameterValueException("accountName and projectId are mutually exclusive");
+            }
+            Project project = _projectMgr.getProject(projectId);
+            if (project == null) {
+                throw new InvalidParameterValueException("Unable to find project by id " + projectId);
+            }
+            vlanOwner = _accountMgr.getAccount(project.getProjectAccountId());
+        }
+
+        if ((accountName != null) && (domainId != null)) {
+            vlanOwner = _accountDao.findActiveAccount(accountName, domainId);
+            if (vlanOwner == null) {
+                throw new InvalidParameterValueException("Please specify a valid account");
+            }
+        }
+
+        // Check if range is valid
+        VlanVO vlan = _vlanDao.findById(vlanDbId);
+        if (vlan == null) {
+            throw new InvalidParameterValueException("Please specify a valid Public IP range id");
+        }
+
+        // Check if range has already been dedicated
+        List<AccountVlanMapVO> maps = _accountVlanMapDao.listAccountVlanMapsByVlan(vlanDbId);
+        if (maps != null && !maps.isEmpty()) {
+            throw new InvalidParameterValueException("Specified Public IP range has already been dedicated");
+        }
+
+        // Verify that zone exists and is advanced
+        Long zoneId = vlan.getDataCenterId();
+        DataCenterVO zone = _zoneDao.findById(zoneId);
+        if (zone == null) {
+            throw new InvalidParameterValueException("Unable to find zone by id " + zoneId);
+        }
+        if (zone.getNetworkType() == NetworkType.Basic) {
+            throw new InvalidParameterValueException("Public IP range can be dedicated to an account only in the zone of type " + NetworkType.Advanced);
+        }
+
+        // Check Public IP resource limits
+        int accountPublicIpRange = _publicIpAddressDao.countIPs(zoneId, vlanDbId, false);
+        _resourceLimitMgr.checkResourceLimit(vlanOwner, ResourceType.public_ip, accountPublicIpRange);
+
+        // Check if any of the Public IP addresses is allocated to another account
+        List<IPAddressVO> ips = _publicIpAddressDao.listByVlanId(vlanDbId);
+        for (IPAddressVO ip : ips) {
+            Long allocatedToAccountId = ip.getAllocatedToAccountId();
+            if (allocatedToAccountId != null) {
+                Account accountAllocatedTo = _accountMgr.getActiveAccountById(allocatedToAccountId);
+                if (!accountAllocatedTo.getAccountName().equalsIgnoreCase(accountName))
+                    throw new InvalidParameterValueException("Public IP address in range is already allocated to another account");
+            }
+        }
+
+        Transaction txn = Transaction.currentTxn();
+        txn.start();
+
+        // Create an AccountVlanMapVO entry
+        AccountVlanMapVO accountVlanMapVO = new AccountVlanMapVO(vlanOwner.getId(), vlan.getId());
+        _accountVlanMapDao.persist(accountVlanMapVO);
+
+        txn.commit();
+
+        return vlan;
+    }
+
+    @Override
+    @ActionEvent(eventType = EventTypes.EVENT_VLAN_IP_RANGE_RELEASE, eventDescription = "releasing a public ip range", async = false)
+    public boolean releasePublicIpRange(ReleasePublicIpRangeCmd cmd) {
+        Long vlanDbId = cmd.getId();
+
+        VlanVO vlan = _vlanDao.findById(vlanDbId);
+        if (vlan == null) {
+            throw new InvalidParameterValueException("Please specify a valid IP range id.");
+        }
+
+        return releasePublicIpRange(vlanDbId, UserContext.current().getCallerUserId(), UserContext.current().getCaller());
+    }
+
+    @Override
+    @DB
+    public boolean releasePublicIpRange(long vlanDbId, long userId, Account caller) {
+        VlanVO vlan = _vlanDao.findById(vlanDbId);
+
+        List<AccountVlanMapVO> acctVln = _accountVlanMapDao.listAccountVlanMapsByVlan(vlanDbId);
+        // Verify range is dedicated
+        if (acctVln == null || acctVln.isEmpty()) {
+            throw new InvalidParameterValueException("Can't release Public IP range " + vlanDbId + " as it not dedicated to any account");
+        }
+
+        // Check if range has any allocated public IPs
+        long allocIpCount = _publicIpAddressDao.countIPs(vlan.getDataCenterId(), vlanDbId, true);
+        boolean success = true;
+        if (allocIpCount > 0) {
+            try {
+                vlan = _vlanDao.acquireInLockTable(vlanDbId, 30);
+                if (vlan == null) {
+                    throw new CloudRuntimeException("Unable to acquire vlan configuration: " + vlanDbId);
+                }
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug("lock vlan " + vlanDbId + " is acquired");
+                }
+                List<IPAddressVO> ips = _publicIpAddressDao.listByVlanId(vlanDbId);
+                for (IPAddressVO ip : ips) {
+                    // Disassociate allocated IP's that are not in use
+                    if ( !ip.isOneToOneNat() && !(ip.isSourceNat() && _networkModel.getNetwork(ip.getAssociatedWithNetworkId()) != null) &&
+                            !(_firewallDao.countRulesByIpId(ip.getId()) > 0) ) {
+                        if (s_logger.isDebugEnabled()) {
+                            s_logger.debug("Releasing Public IP addresses" + ip  +" of vlan " + vlanDbId + " as part of Public IP" +
+                                    " range release to the system pool");
+                        }
+                        success = success && _networkMgr.disassociatePublicIpAddress(ip.getId(), userId, caller);
+                    }
+                }
+                if (!success) {
+                    s_logger.warn("Some Public IP addresses that were not in use failed to be released as a part of" +
+                            " vlan " + vlanDbId + "release to the system pool");
+                }
+            } finally {
+                _vlanDao.releaseFromLockTable(vlanDbId);
+            }
+        }
+
+        // A Public IP range can only be dedicated to one account at a time
+        if (_accountVlanMapDao.remove(acctVln.get(0).getId())) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    @Override
     public List<String> csvTagsToList(String tags) {
         List<String> tagsList = new ArrayList<String>();
 
@@ -3957,14 +4082,14 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
 
     @Override
     @DB
-    public boolean deleteAccountSpecificVirtualRanges(long accountId) {
+    public boolean releaseAccountSpecificVirtualRanges(long accountId) {
         List<AccountVlanMapVO> maps = _accountVlanMapDao.listAccountVlanMapsByAccount(accountId);
         boolean result = true;
         if (maps != null && !maps.isEmpty()) {
             Transaction txn = Transaction.currentTxn();
             txn.start();
             for (AccountVlanMapVO map : maps) {
-                if (!deleteVlanAndPublicIpRange(_accountMgr.getSystemUser().getId(), map.getVlanDbId(), 
+                if (!releasePublicIpRange(map.getVlanDbId(), _accountMgr.getSystemUser().getId(),
                         _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM))) {
                     result = false;
                 }
@@ -3972,10 +4097,10 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
             if (result) {
                 txn.commit();
             } else {
-                s_logger.error("Failed to delete account specific virtual ip ranges for account id=" + accountId);
+                s_logger.error("Failed to release account specific virtual ip ranges for account id=" + accountId);
             }
         } else {
-            s_logger.trace("Account id=" + accountId + " has no account specific virtual ip ranges, nothing to delete");
+            s_logger.trace("Account id=" + accountId + " has no account specific virtual ip ranges, nothing to release");
         }
         return result;
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f865c5a/server/src/com/cloud/network/NetworkManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java
index a97f2ce..5b60466 100755
--- a/server/src/com/cloud/network/NetworkManagerImpl.java
+++ b/server/src/com/cloud/network/NetworkManagerImpl.java
@@ -348,7 +348,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
     }
 
     @DB
-    public PublicIp fetchNewPublicIp(long dcId, Long podId, Long vlanDbId, Account owner, VlanType vlanUse,
+    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 ");
@@ -364,9 +364,9 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
             errorMessage.append(" zone id=" + dcId);
         }
 
-        if (vlanDbId != null) {
-            sc.addAnd("vlanId", SearchCriteria.Op.EQ, vlanDbId);
-            errorMessage.append(", vlanId id=" + vlanDbId);
+        if ( vlanDbIds != null && !vlanDbIds.isEmpty() ) {
+            sc.setParameters("vlanId", vlanDbIds.toArray());
+            errorMessage.append(", vlanId id=" + vlanDbIds.toArray());
         }
 
         sc.setParameters("dc", dcId);
@@ -526,14 +526,14 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
             }
 
             // If account has Account specific ip ranges, try to allocate ip from there
-            Long vlanId = null;
+            List<Long> vlanIds = new ArrayList<Long>();
             List<AccountVlanMapVO> maps = _accountVlanMapDao.listAccountVlanMapsByAccount(ownerId);
             if (maps != null && !maps.isEmpty()) {
-                vlanId = maps.get(0).getVlanDbId();
+                vlanIds.add(maps.get(0).getVlanDbId());
             }
 
 
-            ip = fetchNewPublicIp(dcId, null, vlanId, owner, VlanType.VirtualNetwork, guestNtwkId,
+            ip = fetchNewPublicIp(dcId, null, vlanIds, owner, VlanType.VirtualNetwork, guestNtwkId,
                     isSourceNat, false, null, false, vpcId);
             IPAddressVO publicIp = ip.ip();
 
@@ -669,6 +669,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
 
         VlanType vlanType = VlanType.VirtualNetwork;
         boolean assign = false;
+        boolean allocateFromDedicatedRange = false;
 
         if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getType())) {
             // zone is of type DataCenter. See DataCenterVO.java.
@@ -702,8 +703,32 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
 
             txn.start();
 
-            ip = fetchNewPublicIp(zone.getId(), null, null, ipOwner, vlanType, null,
-                    false, assign, null, isSystem, null);
+            // If account has dedicated Public IP ranges, allocate IP from the dedicated range
+            List<Long> vlanDbIds = new ArrayList<Long>();
+            List<AccountVlanMapVO> maps = _accountVlanMapDao.listAccountVlanMapsByAccount(ipOwner.getId());
+            for (AccountVlanMapVO map : maps) {
+                vlanDbIds.add(map.getVlanDbId());
+            }
+            if (vlanDbIds != null && !vlanDbIds.isEmpty()) {
+                allocateFromDedicatedRange = true;
+            }
+
+            try {
+                if (allocateFromDedicatedRange) {
+                    ip = fetchNewPublicIp(zone.getId(), null, vlanDbIds, ipOwner, vlanType, null,
+                            false, assign, null, isSystem, null);
+                }
+            } catch(InsufficientAddressCapacityException e) {
+                s_logger.warn("All IPs dedicated to account " + ipOwner.getId() + " has been acquired." +
+                        " Now acquiring from the system pool");
+                txn.close();
+                allocateFromDedicatedRange = false;
+            }
+
+            if (!allocateFromDedicatedRange) {
+                ip = fetchNewPublicIp(zone.getId(), null, null, ipOwner, vlanType, null, false, assign, null,
+                       isSystem, null);
+            }
 
             if (ip == null) {
 
@@ -1082,7 +1107,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
         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.EQ);
+        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);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f865c5a/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 4eb620c..a8cbaa7 100755
--- a/server/src/com/cloud/network/NetworkServiceImpl.java
+++ b/server/src/com/cloud/network/NetworkServiceImpl.java
@@ -697,15 +697,6 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
             throw new IllegalArgumentException("only ip addresses that belong to a virtual network may be disassociated.");
         }
 
-        // Check for account wide pool. It will have an entry for account_vlan_map.
-        if (_accountVlanMapDao.findAccountVlanMap(ipVO.getAllocatedToAccountId(), ipVO.getVlanId()) != null) {            
-            //see IPaddressVO.java
-            InvalidParameterValueException ex = new InvalidParameterValueException("Sepcified IP address uuid belongs to" +
-                    " Account wide IP pool and cannot be disassociated");
-            ex.addProxyObject("user_ip_address", ipAddressId, "ipAddressId");
-            throw ex;
-        }
-
         // don't allow releasing system ip address
         if (ipVO.getSystem()) {
             InvalidParameterValueException ex = new InvalidParameterValueException("Can't release system IP address with specified id");

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f865c5a/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 b869d1e..d9a4317 100755
--- a/server/src/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/com/cloud/server/ManagementServerImpl.java
@@ -59,6 +59,7 @@ import org.apache.cloudstack.api.command.admin.storage.*;
 import org.apache.cloudstack.api.command.admin.systemvm.*;
 import org.apache.cloudstack.api.command.admin.usage.*;
 import org.apache.cloudstack.api.command.admin.user.*;
+import org.apache.cloudstack.api.command.admin.vlan.*;
 import org.apache.cloudstack.api.command.admin.vpc.*;
 import org.apache.cloudstack.api.command.user.autoscale.*;
 import org.apache.cloudstack.api.command.user.firewall.*;
@@ -2037,6 +2038,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
         cmdList.add(CreateVlanIpRangeCmd.class);
         cmdList.add(DeleteVlanIpRangeCmd.class);
         cmdList.add(ListVlanIpRangesCmd.class);
+        cmdList.add(DedicatePublicIpRangeCmd.class);
+        cmdList.add(ReleasePublicIpRangeCmd.class);
         cmdList.add(AssignVMCmd.class);
         cmdList.add(MigrateVMCmd.class);
         cmdList.add(RecoverVMCmd.class);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f865c5a/server/src/com/cloud/user/AccountManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java
index fe714c5..e74c491 100755
--- a/server/src/com/cloud/user/AccountManagerImpl.java
+++ b/server/src/com/cloud/user/AccountManagerImpl.java
@@ -690,13 +690,13 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
                 accountCleanupNeeded = true;
             }
 
-            // delete account specific Virtual vlans (belong to system Public Network) - only when networks are cleaned
+            // release account specific Virtual vlans (belong to system Public Network) - only when networks are cleaned
             // up successfully
             if (networksDeleted) {
-                if (!_configMgr.deleteAccountSpecificVirtualRanges(accountId)) {
+                if (!_configMgr.releaseAccountSpecificVirtualRanges(accountId)) {
                     accountCleanupNeeded = true;
                 } else {
-                    s_logger.debug("Account specific Virtual IP ranges " + " are successfully deleted as a part of account id=" + accountId + " cleanup.");
+                    s_logger.debug("Account specific Virtual IP ranges " + " are successfully released as a part of account id=" + accountId + " cleanup.");
                 }
             }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f865c5a/server/test/com/cloud/configuration/ConfigurationManagerTest.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/configuration/ConfigurationManagerTest.java b/server/test/com/cloud/configuration/ConfigurationManagerTest.java
new file mode 100755
index 0000000..ee98d53
--- /dev/null
+++ b/server/test/com/cloud/configuration/ConfigurationManagerTest.java
@@ -0,0 +1,413 @@
+// 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.configuration;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.lang.reflect.Field;
+
+import org.apache.cloudstack.api.command.admin.vlan.DedicatePublicIpRangeCmd;
+import org.apache.cloudstack.api.command.admin.vlan.ReleasePublicIpRangeCmd;
+import org.apache.log4j.Logger;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import com.cloud.configuration.Resource.ResourceType;
+import com.cloud.dc.AccountVlanMapVO;
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.Vlan;
+import com.cloud.dc.VlanVO;
+import com.cloud.dc.DataCenter.NetworkType;
+import com.cloud.dc.dao.AccountVlanMapDao;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.dc.dao.VlanDao;
+import com.cloud.network.NetworkManager;
+import com.cloud.network.dao.FirewallRulesDao;
+import com.cloud.network.dao.IPAddressDao;
+import com.cloud.network.dao.IPAddressVO;
+import com.cloud.projects.ProjectManager;
+import com.cloud.user.Account;
+import com.cloud.user.AccountManager;
+import com.cloud.user.AccountVO;
+import com.cloud.user.ResourceLimitService;
+import com.cloud.user.UserContext;
+import com.cloud.user.dao.AccountDao;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.net.Ip;
+
+import junit.framework.Assert;
+
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.doNothing;
+
+public class ConfigurationManagerTest {
+
+    private static final Logger s_logger = Logger.getLogger(ConfigurationManagerTest.class);
+
+    ConfigurationManagerImpl configurationMgr = new ConfigurationManagerImpl();
+
+    DedicatePublicIpRangeCmd dedicatePublicIpRangesCmd = new DedicatePublicIpRangeCmdExtn();
+    Class<?> _dedicatePublicIpRangeClass = dedicatePublicIpRangesCmd.getClass().getSuperclass();
+
+    ReleasePublicIpRangeCmd releasePublicIpRangesCmd = new ReleasePublicIpRangeCmdExtn();
+    Class<?> _releasePublicIpRangeClass = releasePublicIpRangesCmd.getClass().getSuperclass();
+
+    @Mock AccountManager _accountMgr;
+    @Mock ProjectManager _projectMgr;
+    @Mock ResourceLimitService _resourceLimitMgr;
+    @Mock NetworkManager _networkMgr;
+    @Mock AccountDao _accountDao;
+    @Mock VlanDao _vlanDao;
+    @Mock AccountVlanMapDao _accountVlanMapDao;
+    @Mock IPAddressDao _publicIpAddressDao;
+    @Mock DataCenterDao _zoneDao;
+    @Mock FirewallRulesDao _firewallDao;
+
+    VlanVO vlan = new VlanVO(Vlan.VlanType.VirtualNetwork, "vlantag", "vlangateway","vlannetmask", 1L, "iprange", 1L, 1L, null, null, null);
+
+    @Before
+    public void setup() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        configurationMgr._accountMgr = _accountMgr;
+        configurationMgr._projectMgr = _projectMgr;
+        configurationMgr._resourceLimitMgr = _resourceLimitMgr;
+        configurationMgr._networkMgr = _networkMgr;
+        configurationMgr._accountDao = _accountDao;
+        configurationMgr._vlanDao = _vlanDao;
+        configurationMgr._accountVlanMapDao = _accountVlanMapDao;
+        configurationMgr._publicIpAddressDao = _publicIpAddressDao;
+        configurationMgr._zoneDao = _zoneDao;
+        configurationMgr._firewallDao = _firewallDao;
+
+        Account account = (Account) new AccountVO("testaccount", 1, "networkdomain", (short) 0, UUID.randomUUID().toString());
+        when(configurationMgr._accountMgr.getAccount(anyLong())).thenReturn(account);
+        when(configurationMgr._accountDao.findActiveAccount(anyString(), anyLong())).thenReturn(account);
+        when(configurationMgr._accountMgr.getActiveAccountById(anyLong())).thenReturn(account);
+
+        when(configurationMgr._publicIpAddressDao.countIPs(anyLong(), anyLong(), anyBoolean())).thenReturn(1);
+
+        doNothing().when(configurationMgr._resourceLimitMgr).checkResourceLimit(any(Account.class),
+                any(ResourceType.class), anyLong());
+
+        when(configurationMgr._accountVlanMapDao.persist(any(AccountVlanMapVO.class))).thenReturn(new AccountVlanMapVO());
+
+        when(configurationMgr._vlanDao.acquireInLockTable(anyLong(), anyInt())).thenReturn(vlan);
+
+        UserContext.registerContext(1, account, null, true);
+
+        Field dedicateIdField = _dedicatePublicIpRangeClass.getDeclaredField("id");
+        dedicateIdField.setAccessible(true);
+        dedicateIdField.set(dedicatePublicIpRangesCmd, 1L);
+
+        Field accountNameField = _dedicatePublicIpRangeClass.getDeclaredField("accountName");
+        accountNameField.setAccessible(true);
+        accountNameField.set(dedicatePublicIpRangesCmd, "accountname");
+
+        Field projectIdField = _dedicatePublicIpRangeClass.getDeclaredField("projectId");
+        projectIdField.setAccessible(true);
+        projectIdField.set(dedicatePublicIpRangesCmd, null);
+
+        Field domainIdField = _dedicatePublicIpRangeClass.getDeclaredField("domainId");
+        domainIdField.setAccessible(true);
+        domainIdField.set(dedicatePublicIpRangesCmd, 1L);
+
+        Field releaseIdField = _releasePublicIpRangeClass.getDeclaredField("id");
+        releaseIdField.setAccessible(true);
+        releaseIdField.set(releasePublicIpRangesCmd, 1L);
+    }
+
+    @Test
+    public void testDedicatePublicIpRange() throws Exception {
+
+        s_logger.info("Running tests for DedicatePublicIpRange API");
+
+        /*
+         * TEST 1: given valid parameters DedicatePublicIpRange should succeed
+         */
+        runDedicatePublicIpRangePostiveTest();
+
+        /*
+         * TEST 2: given invalid public ip range DedicatePublicIpRange should fail
+         */
+        runDedicatePublicIpRangeInvalidRange();
+         /*
+         * TEST 3: given public IP range that is already dedicated to a different account DedicatePublicIpRange should fail
+         */
+        runDedicatePublicIpRangeDedicatedRange();
+
+         /*
+         * TEST 4: given zone is of type Basic DedicatePublicIpRange should fail
+         */
+        runDedicatePublicIpRangeInvalidZone();
+
+        /*
+         * TEST 5: given range is already allocated to a different account DedicatePublicIpRange should fail
+         */
+        runDedicatePublicIpRangeIPAdressAllocated();
+    }
+
+    @Test
+    public void testReleasePublicIpRange() throws Exception {
+
+        s_logger.info("Running tests for DedicatePublicIpRange API");
+
+        /*
+         * TEST 1: given valid parameters and no allocated public ip's in the range ReleasePublicIpRange should succeed
+         */
+        runReleasePublicIpRangePostiveTest1();
+
+        /*
+         * TEST 2: given valid parameters ReleasePublicIpRange should succeed
+         */
+        runReleasePublicIpRangePostiveTest2();
+
+        /*
+         * TEST 3: given range doesn't exist
+         */
+        runReleasePublicIpRangeInvalidIpRange();
+
+        /*
+         * TEST 4: given range is not dedicated to any account
+         */
+        runReleaseNonDedicatedPublicIpRange();
+    }
+
+    void runDedicatePublicIpRangePostiveTest() throws Exception {
+        Transaction txn = Transaction.open("runDedicatePublicIpRangePostiveTest");
+
+        when(configurationMgr._vlanDao.findById(anyLong())).thenReturn(vlan);
+
+        when(configurationMgr._accountVlanMapDao.listAccountVlanMapsByAccount(anyLong())).thenReturn(null);
+
+        DataCenterVO dc = new DataCenterVO(UUID.randomUUID().toString(), "test", "8.8.8.8", null, "10.0.0.1", null,  "10.0.0.1/24",
+                null, null, NetworkType.Advanced, null, null, true,  true, null, null);
+        when(configurationMgr._zoneDao.findById(anyLong())).thenReturn(dc);
+
+        List<IPAddressVO> ipAddressList = new ArrayList<IPAddressVO>();
+        IPAddressVO ipAddress = new IPAddressVO(new Ip("75.75.75.75"), 1, 0xaabbccddeeffL, 10, false);
+        ipAddressList.add(ipAddress);
+        when(configurationMgr._publicIpAddressDao.listByVlanId(anyLong())).thenReturn(ipAddressList);
+
+        try {
+            Vlan result = configurationMgr.dedicatePublicIpRange(dedicatePublicIpRangesCmd);
+            Assert.assertNotNull(result);
+        } catch (Exception e) {
+            s_logger.info("exception in testing runDedicatePublicIpRangePostiveTest message: " + e.toString());
+        } finally {
+            txn.close("runDedicatePublicIpRangePostiveTest");
+        }
+    }
+
+    void runDedicatePublicIpRangeInvalidRange() throws Exception {
+        Transaction txn = Transaction.open("runDedicatePublicIpRangeInvalidRange");
+
+        when(configurationMgr._vlanDao.findById(anyLong())).thenReturn(null);
+        try {
+            configurationMgr.dedicatePublicIpRange(dedicatePublicIpRangesCmd);
+        } catch (Exception e) {
+            Assert.assertTrue(e.getMessage().contains("Please specify a valid Public IP range id"));
+        } finally {
+            txn.close("runDedicatePublicIpRangeInvalidRange");
+        }
+    }
+
+    void runDedicatePublicIpRangeDedicatedRange() throws Exception {
+        Transaction txn = Transaction.open("runDedicatePublicIpRangeDedicatedRange");
+
+        when(configurationMgr._vlanDao.findById(anyLong())).thenReturn(vlan);
+
+        // public ip range is already dedicated
+        List<AccountVlanMapVO> accountVlanMaps = new ArrayList<AccountVlanMapVO>();
+        AccountVlanMapVO accountVlanMap = new AccountVlanMapVO(1, 1);
+        accountVlanMaps.add(accountVlanMap);
+        when(configurationMgr._accountVlanMapDao.listAccountVlanMapsByVlan(anyLong())).thenReturn(accountVlanMaps);
+
+        DataCenterVO dc = new DataCenterVO(UUID.randomUUID().toString(), "test", "8.8.8.8", null, "10.0.0.1", null,  "10.0.0.1/24",
+                null, null, NetworkType.Advanced, null, null, true,  true, null, null);
+        when(configurationMgr._zoneDao.findById(anyLong())).thenReturn(dc);
+
+        List<IPAddressVO> ipAddressList = new ArrayList<IPAddressVO>();
+        IPAddressVO ipAddress = new IPAddressVO(new Ip("75.75.75.75"), 1, 0xaabbccddeeffL, 10, false);
+        ipAddressList.add(ipAddress);
+        when(configurationMgr._publicIpAddressDao.listByVlanId(anyLong())).thenReturn(ipAddressList);
+
+        try {
+            configurationMgr.dedicatePublicIpRange(dedicatePublicIpRangesCmd);
+        } catch (Exception e) {
+            Assert.assertTrue(e.getMessage().contains("Public IP range has already been dedicated"));
+        } finally {
+            txn.close("runDedicatePublicIpRangePublicIpRangeDedicated");
+        }
+    }
+
+    void runDedicatePublicIpRangeInvalidZone() throws Exception {
+        Transaction txn = Transaction.open("runDedicatePublicIpRangeInvalidZone");
+
+        when(configurationMgr._vlanDao.findById(anyLong())).thenReturn(vlan);
+
+        when(configurationMgr._accountVlanMapDao.listAccountVlanMapsByVlan(anyLong())).thenReturn(null);
+
+        // public ip range belongs to zone of type basic
+        DataCenterVO dc = new DataCenterVO(UUID.randomUUID().toString(), "test", "8.8.8.8", null, "10.0.0.1", null,  "10.0.0.1/24",
+                null, null, NetworkType.Basic, null, null, true,  true, null, null);
+        when(configurationMgr._zoneDao.findById(anyLong())).thenReturn(dc);
+
+        List<IPAddressVO> ipAddressList = new ArrayList<IPAddressVO>();
+        IPAddressVO ipAddress = new IPAddressVO(new Ip("75.75.75.75"), 1, 0xaabbccddeeffL, 10, false);
+        ipAddressList.add(ipAddress);
+        when(configurationMgr._publicIpAddressDao.listByVlanId(anyLong())).thenReturn(ipAddressList);
+
+        try {
+            configurationMgr.dedicatePublicIpRange(dedicatePublicIpRangesCmd);
+        } catch (Exception e) {
+            Assert.assertTrue(e.getMessage().contains("Public IP range can be dedicated to an account only in the zone of type Advanced"));
+        } finally {
+            txn.close("runDedicatePublicIpRangeInvalidZone");
+        }
+    }
+
+    void runDedicatePublicIpRangeIPAdressAllocated() throws Exception {
+        Transaction txn = Transaction.open("runDedicatePublicIpRangeIPAdressAllocated");
+
+        when(configurationMgr._vlanDao.findById(anyLong())).thenReturn(vlan);
+
+        when(configurationMgr._accountVlanMapDao.listAccountVlanMapsByAccount(anyLong())).thenReturn(null);
+
+        DataCenterVO dc = new DataCenterVO(UUID.randomUUID().toString(), "test", "8.8.8.8", null, "10.0.0.1", null,  "10.0.0.1/24",
+                null, null, NetworkType.Advanced, null, null, true,  true, null, null);
+        when(configurationMgr._zoneDao.findById(anyLong())).thenReturn(dc);
+
+        // one of the ip addresses of the range is allocated to different account
+        List<IPAddressVO> ipAddressList = new ArrayList<IPAddressVO>();
+        IPAddressVO ipAddress = new IPAddressVO(new Ip("75.75.75.75"), 1, 0xaabbccddeeffL, 10, false);
+        ipAddress.setAllocatedToAccountId(1L);
+        ipAddressList.add(ipAddress);
+        when(configurationMgr._publicIpAddressDao.listByVlanId(anyLong())).thenReturn(ipAddressList);
+
+        try {
+            configurationMgr.dedicatePublicIpRange(dedicatePublicIpRangesCmd);
+        } catch (Exception e) {
+            Assert.assertTrue(e.getMessage().contains("Public IP address in range is already allocated to another account"));
+        } finally {
+            txn.close("runDedicatePublicIpRangeIPAdressAllocated");
+        }
+    }
+
+    void runReleasePublicIpRangePostiveTest1() throws Exception {
+        Transaction txn = Transaction.open("runReleasePublicIpRangePostiveTest1");
+
+        when(configurationMgr._vlanDao.findById(anyLong())).thenReturn(vlan);
+
+        List<AccountVlanMapVO> accountVlanMaps = new ArrayList<AccountVlanMapVO>();
+        AccountVlanMapVO accountVlanMap = new AccountVlanMapVO(1, 1);
+        accountVlanMaps.add(accountVlanMap);
+        when(configurationMgr._accountVlanMapDao.listAccountVlanMapsByVlan(anyLong())).thenReturn(accountVlanMaps);
+
+        // no allocated ip's
+        when(configurationMgr._publicIpAddressDao.countIPs(anyLong(), anyLong(), anyBoolean())).thenReturn(0);
+
+        when(configurationMgr._accountVlanMapDao.remove(anyLong())).thenReturn(true);
+        try {
+            Boolean result = configurationMgr.releasePublicIpRange(releasePublicIpRangesCmd);
+            Assert.assertTrue(result);
+        } catch (Exception e) {
+            s_logger.info("exception in testing runReleasePublicIpRangePostiveTest1 message: " + e.toString());
+        } finally {
+            txn.close("runReleasePublicIpRangePostiveTest1");
+        }
+    }
+
+    void runReleasePublicIpRangePostiveTest2() throws Exception {
+        Transaction txn = Transaction.open("runReleasePublicIpRangePostiveTest2");
+
+        when(configurationMgr._vlanDao.findById(anyLong())).thenReturn(vlan);
+
+        List<AccountVlanMapVO> accountVlanMaps = new ArrayList<AccountVlanMapVO>();
+        AccountVlanMapVO accountVlanMap = new AccountVlanMapVO(1, 1);
+        accountVlanMaps.add(accountVlanMap);
+        when(configurationMgr._accountVlanMapDao.listAccountVlanMapsByVlan(anyLong())).thenReturn(accountVlanMaps);
+
+        when(configurationMgr._publicIpAddressDao.countIPs(anyLong(), anyLong(), anyBoolean())).thenReturn(1);
+
+        List<IPAddressVO> ipAddressList = new ArrayList<IPAddressVO>();
+        IPAddressVO ipAddress = new IPAddressVO(new Ip("75.75.75.75"), 1, 0xaabbccddeeffL, 10, false);
+        ipAddressList.add(ipAddress);
+        when(configurationMgr._publicIpAddressDao.listByVlanId(anyLong())).thenReturn(ipAddressList);
+
+        when(configurationMgr._firewallDao.countRulesByIpId(anyLong())).thenReturn(0L);
+
+        when(configurationMgr._networkMgr.disassociatePublicIpAddress(anyLong(), anyLong(), any(Account.class))).thenReturn(true);
+
+        when(configurationMgr._vlanDao.releaseFromLockTable(anyLong())).thenReturn(true);
+
+        when(configurationMgr._accountVlanMapDao.remove(anyLong())).thenReturn(true);
+        try {
+            Boolean result = configurationMgr.releasePublicIpRange(releasePublicIpRangesCmd);
+            Assert.assertTrue(result);
+        } catch (Exception e) {
+            s_logger.info("exception in testing runReleasePublicIpRangePostiveTest2 message: " + e.toString());
+        } finally {
+            txn.close("runReleasePublicIpRangePostiveTest2");
+        }
+    }
+
+    void runReleasePublicIpRangeInvalidIpRange() throws Exception {
+        Transaction txn = Transaction.open("runReleasePublicIpRangeInvalidIpRange");
+
+        when(configurationMgr._vlanDao.findById(anyLong())).thenReturn(null);
+        try {
+            configurationMgr.releasePublicIpRange(releasePublicIpRangesCmd);
+        } catch (Exception e) {
+            Assert.assertTrue(e.getMessage().contains("Please specify a valid IP range id"));
+        } finally {
+            txn.close("runReleasePublicIpRangeInvalidIpRange");
+        }
+    }
+
+    void runReleaseNonDedicatedPublicIpRange() throws Exception {
+        Transaction txn = Transaction.open("runReleaseNonDedicatedPublicIpRange");
+
+        when(configurationMgr._vlanDao.findById(anyLong())).thenReturn(vlan);
+
+        when(configurationMgr._accountVlanMapDao.listAccountVlanMapsByVlan(anyLong())).thenReturn(null);
+        try {
+            configurationMgr.releasePublicIpRange(releasePublicIpRangesCmd);
+        } catch (Exception e) {
+            Assert.assertTrue(e.getMessage().contains("as it not dedicated to any account"));
+        } finally {
+            txn.close("runReleaseNonDedicatedPublicIpRange");
+        }
+    }
+
+
+    public class DedicatePublicIpRangeCmdExtn extends DedicatePublicIpRangeCmd {
+        public long getEntityOwnerId() {
+            return 1;
+        }
+    }
+
+    public class ReleasePublicIpRangeCmdExtn extends ReleasePublicIpRangeCmd {
+        public long getEntityOwnerId() {
+            return 1;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f865c5a/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
old mode 100644
new mode 100755
index b0063fa..a03e361
--- a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
+++ b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
@@ -40,7 +40,9 @@ 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.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;
@@ -544,7 +546,7 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu
      * @see com.cloud.configuration.ConfigurationManager#deleteAccountSpecificVirtualRanges(long)
      */
     @Override
-    public boolean deleteAccountSpecificVirtualRanges(long accountId) {
+    public boolean releaseAccountSpecificVirtualRanges(long accountId) {
         // TODO Auto-generated method stub
         return false;
     }
@@ -613,5 +615,24 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu
         return null;
     }
 
+	@Override
+	public Vlan dedicatePublicIpRange(DedicatePublicIpRangeCmd cmd)
+			throws ResourceAllocationException {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	@Override
+	public boolean releasePublicIpRange(ReleasePublicIpRangeCmd cmd) {
+		// TODO Auto-generated method stub
+		return false;
+	}
+
+	@Override
+	public boolean releasePublicIpRange(long userId, long vlanDbId,
+			Account caller) {
+		// TODO Auto-generated method stub
+		return false;
+	}
 
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f865c5a/test/integration/component/test_public_ip_range.py
----------------------------------------------------------------------
diff --git a/test/integration/component/test_public_ip_range.py b/test/integration/component/test_public_ip_range.py
new file mode 100755
index 0000000..f2c967f
--- /dev/null
+++ b/test/integration/component/test_public_ip_range.py
@@ -0,0 +1,173 @@
+# 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.
+""" P1 tests for Dedicating Public IP addresses
+"""
+#Import Local Modules
+import marvin
+from nose.plugins.attrib import attr
+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 *
+import datetime
+
+class Services:
+    """Test Dedicating Public IP addresses
+    """
+
+    def __init__(self):
+        self.services = {
+                        "domain": {
+                                   "name": "Domain",
+                                   },
+                        "account": {
+                                    "email": "test@test.com",
+                                    "firstname": "Test",
+                                    "lastname": "User",
+                                    "username": "test",
+                                    "password": "password",
+                         },
+                        "gateway": "10.102.197.1",
+                        "netmask": "255.255.255.0",
+                        "forvirtualnetwork": "true",
+                        "startip": "10.102.197.70",
+                        "endip": "10.102.197.73",
+                        "zoneid": "1",
+                        "podid": "",
+                        "vlan": "101",
+                    }
+
+class TesDedicatePublicIPRange(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        cls.api_client = super(TesDedicatePublicIPRange, 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 = ["publiciprange", "dedicate", "release"])
+    def test_dedicatePublicIpRange(self):
+        """Test public IP range dedication
+        """
+
+        # Validate the following:
+        # 1. Create a Public IP range
+        # 2. Created IP range should be present, verify with listVlanIpRanges
+        # 3. Dedicate the created IP range to user account
+        # 4. Verify IP range is dedicated, verify with listVlanIpRanges
+        # 5. Release the dedicated Public IP range back to the system
+        # 6. Verify IP range has been released, verify with listVlanIpRanges
+        # 7. Delete the Public IP range
+
+        self.debug("Creating Public IP range")
+        self.public_ip_range = PublicIpRange.create(
+                                    self.api_client,
+                                    self.services
+                               )
+        list_public_ip_range_response = PublicIpRange.list(
+                                            self.apiclient,
+                                            id=self.public_ip_range.vlan.id
+                                        )
+        self.debug(
+                "Verify listPublicIpRanges response for public ip ranges: %s" \
+                % self.public_ip_range.vlan.id
+            )
+        self.assertEqual(
+                         isinstance(list_public_ip_range_response, list),
+                         True,
+                         "Check for list Public IP range response"
+                         )
+        public_ip_response = list_public_ip_range_response[0]
+        self.assertEqual(
+                            public_ip_response.id,
+                            self.public_ip_range.vlan.id,
+                            "Check public ip range response id is in listVlanIpRanges"
+                        )
+
+        self.debug("Dedicating Public IP range");
+        dedicate_public_ip_range_response = PublicIpRange.dedicate(
+                                                self.apiclient,
+                                                self.public_ip_range.vlan.id,
+                                                account=self.account.account.name,
+                                                domainid=self.account.account.domainid
+                                            )
+        list_public_ip_range_response = PublicIpRange.list(
+                                            self.apiclient,
+                                            id=self.public_ip_range.vlan.id
+                                        )
+        public_ip_response = list_public_ip_range_response[0]
+        self.assertEqual(
+                            public_ip_response.account,
+                            self.account.account.name,
+                            "Check account name is in listVlanIpRanges as the account public ip range is dedicated to"
+                        )
+
+        self.debug("Releasing Public IP range");
+        self.public_ip_range.release(self.apiclient)
+        list_public_ip_range_response = PublicIpRange.list(
+                                            self.apiclient,
+                                            id=self.public_ip_range.vlan.id
+                                        )
+        public_ip_response = list_public_ip_range_response[0]
+        self.assertEqual(
+                            public_ip_response.account,
+                            "system",
+                            "Check account name is system account in listVlanIpRanges"
+                        )
+
+        self.debug("Deleting Public IP range");
+        self.public_ip_range.delete(self.apiclient)
+
+        return
+

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f865c5a/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
old mode 100644
new mode 100755
index d27ab3b..3df68ab
--- a/tools/marvin/marvin/integration/lib/base.py
+++ b/tools/marvin/marvin/integration/lib/base.py
@@ -1873,7 +1873,7 @@ class PublicIpRange:
         """Delete VlanIpRange"""
 
         cmd = deleteVlanIpRange.deleteVlanIpRangeCmd()
-        cmd.id = self.id
+        cmd.id = self.vlan.id
         apiclient.deleteVlanIpRange(cmd)
 
     @classmethod
@@ -1884,6 +1884,23 @@ class PublicIpRange:
         [setattr(cmd, k, v) for k, v in kwargs.items()]
         return(apiclient.listVlanIpRanges(cmd))
 
+    @classmethod
+    def dedicate(cls, apiclient, id, account=None, domainid=None, projectid=None):
+        """Dedicate VLAN IP range"""
+
+        cmd = dedicatePublicIpRange.dedicatePublicIpRangeCmd()
+        cmd.id = id
+        cmd.account = account
+        cmd.domainid = domainid
+        cmd.projectid = projectid
+        return PublicIpRange(apiclient.dedicatePublicIpRange(cmd).__dict__)
+
+    def release(self, apiclient):
+        """Release VLAN IP range"""
+
+        cmd = releasePublicIpRange.releasePublicIpRangeCmd()
+        cmd.id = self.vlan.id
+        return apiclient.releasePublicIpRange(cmd)
 
 class SecondaryStorage:
     """Manage Secondary storage"""


Mime
View raw message