You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by je...@apache.org on 2013/04/08 23:46:54 UTC

[1/2] git commit: updated refs/heads/master to bf72a36

Updated Branches:
  refs/heads/master 68a30d41d -> bf72a36ea


Dedicate Public IP range


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

Branch: refs/heads/master
Commit: d6ed8d7cb53da08cacd04c3ac7435da5601e7f06
Parents: 68a30d4
Author: Likitha Shetty <li...@citrix.com>
Authored: Thu Apr 4 21:24:41 2013 +0530
Committer: Jessica Wang <je...@citrix.com>
Committed: Mon Apr 8 14:46:21 2013 -0700

----------------------------------------------------------------------
 .../cloud/configuration/ConfigurationService.java  |    6 +
 api/src/com/cloud/event/EventTypes.java            |    2 +
 .../admin/vlan/DedicatePublicIpRangeCmd.java       |  116 +++++
 .../admin/vlan/ReleasePublicIpRangeCmd.java        |   77 +++
 client/tomcatconf/commands.properties.in           |    2 +
 .../cloud/configuration/ConfigurationManager.java  |    7 +-
 .../configuration/ConfigurationManagerImpl.java    |  180 ++++++-
 .../src/com/cloud/network/NetworkManagerImpl.java  |   46 ++-
 .../src/com/cloud/network/NetworkServiceImpl.java  |    9 -
 .../src/com/cloud/server/ManagementServerImpl.java |    2 +
 server/src/com/cloud/user/AccountManagerImpl.java  |    6 +-
 .../configuration/ConfigurationManagerTest.java    |  400 +++++++++++++++
 .../cloud/vpc/MockConfigurationManagerImpl.java    |   32 ++-
 test/integration/component/test_public_ip_range.py |  149 ++++++
 tools/marvin/marvin/integration/lib/base.py        |   11 +
 15 files changed, 997 insertions(+), 48 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6ed8d7c/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/d6ed8d7c/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 704a1bf..0dc16f3 100755
--- a/api/src/com/cloud/event/EventTypes.java
+++ b/api/src/com/cloud/event/EventTypes.java
@@ -223,6 +223,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";

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6ed8d7c/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 100644
index 0000000..c62857c
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/vlan/DedicatePublicIpRangeCmd.java
@@ -0,0 +1,116 @@
+// 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;
+
+    @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.UUID, entityType = ZoneResponse.class,
+            required=true, description="the Zone ID of the VLAN IP range")
+    private Long zoneId;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getId() {
+        return id;
+    }
+
+    public String getAccountName() {
+        return accountName;
+    }
+
+    public Long getDomainId() {
+        return domainId;
+    }
+
+    public Long getProjectId() {
+        return projectId;
+    }
+
+    public Long getZoneId() {
+        return zoneId;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// 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/d6ed8d7c/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/d6ed8d7c/client/tomcatconf/commands.properties.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in
index 163c2ce..3e55672 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/d6ed8d7c/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
index 20e9884..52b32f4 100644
--- 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;
@@ -149,6 +150,10 @@ public interface ConfigurationManager extends ConfigurationService, Manager {
      */
     boolean deleteVlanAndPublicIpRange(long userId, long vlanDbId, Account caller);
 
+    boolean releasePublicIpRange(long userId, long vlanDbId, Account caller);
+
+    Vlan dedicatePublicIpRange(Long vlanDbId, String accountName, Long domainId, Long zoneId, Long projectId) throws ResourceAllocationException;
+
     /**
      * Converts a comma separated list of tags to a List
      * 
@@ -210,7 +215,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/d6ed8d7c/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 1526fb0..86d30b4 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,156 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
     }
 
     @Override
+    @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 zoneId = cmd.getZoneId();
+        Long projectId = cmd.getProjectId();
+
+        Vlan vlan = dedicatePublicIpRange(vlanDbId, accountName, domainId, zoneId, projectId);
+
+        return vlan;
+    }
+
+    @Override
+    @DB
+    public Vlan dedicatePublicIpRange(Long vlanDbId, String accountName, Long domainId, Long zoneId, Long projectId) throws ResourceAllocationException {
+        // 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
+        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 +4089,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 +4104,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/d6ed8d7c/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 6296011..43a0988 100755
--- a/server/src/com/cloud/network/NetworkManagerImpl.java
+++ b/server/src/com/cloud/network/NetworkManagerImpl.java
@@ -188,6 +188,7 @@ import com.cloud.vm.ReservationContextImpl;
 import com.cloud.vm.UserVmVO;
 import com.cloud.vm.VMInstanceVO;
 import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.*;
 import com.cloud.vm.VirtualMachine.Type;
 import com.cloud.vm.VirtualMachineProfile;
 import com.cloud.vm.dao.NicDao;
@@ -348,7 +349,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 +365,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 +527,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 +670,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 +704,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) {
 
@@ -1070,7 +1096,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/d6ed8d7c/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/d6ed8d7c/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 af77ba5..b89de9e 100755
--- a/server/src/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/com/cloud/server/ManagementServerImpl.java
@@ -2090,6 +2090,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/d6ed8d7c/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 52ca79d..417ec3f 100755
--- a/server/src/com/cloud/user/AccountManagerImpl.java
+++ b/server/src/com/cloud/user/AccountManagerImpl.java
@@ -683,13 +683,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/d6ed8d7c/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 100644
index 0000000..eeb1073
--- /dev/null
+++ b/server/test/com/cloud/configuration/ConfigurationManagerTest.java
@@ -0,0 +1,400 @@
+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();
+
+    @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 zoneIdField = _dedicatePublicIpRangeClass.getDeclaredField("zoneId");
+        zoneIdField.setAccessible(true);
+        zoneIdField.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;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6ed8d7c/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 d96e831..f781e61 100644
--- 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,33 @@ 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;
+	}
+
+	@Override
+	public Vlan dedicatePublicIpRange(Long vlanDbId, String accountName,
+			Long domainId, Long zoneId, Long projectId)
+			throws ResourceAllocationException {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
 
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6ed8d7c/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 100644
index 0000000..1cb2e48
--- /dev/null
+++ b/test/integration/component/test_public_ip_range.py
@@ -0,0 +1,149 @@
+# 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",
+                                    # Random characters are appended for unique
+                                    # username
+                                    "password": "password",
+                         },
+                        "gateway": "10.102.196.1",
+                        "netmask": "255.255.255.0",
+                        "forvirtualnetwork": "true",
+                        "startip": "10.102.196.70",
+                        "endip": "10.102.196.73",
+                        "zoneid": "1",
+                        "podid": "",
+                        "vlan": "101",
+                        "sleep": 60,
+                        "timeout": 10,
+                    }
+
+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, VMs etc
+        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"])
+    def test_createPublicIpRange(self):
+        """Test create public IP range
+        """
+
+
+        # Validate the following:
+        # 1. Create public IP range.
+        # 2. Created IP range should be present, verify with listVlanIpRanges
+
+        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");
+        self.debug("Vlan id %s" % self.public_ip_range.vlan.id);
+        self.debug("Zone id %s" % self.zone.id);
+        self.debug("Account name %s" % self.account.account.name);
+        self.debug("Domain id %s" % self.account.account.domainid);
+        dedicate_public_ip_range_response = PublicIpRange.dedicate(
+                                                self.apiclient,
+                                                self.public_ip_range.vlan.id,
+                                                zoneid=self.zone.id,
+                                                account=self.account.account.name,
+                                                domainid=self.account.account.domainid
+                                            )
+        return

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6ed8d7c/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 f3370eb..0e117bb 100644
--- a/tools/marvin/marvin/integration/lib/base.py
+++ b/tools/marvin/marvin/integration/lib/base.py
@@ -1882,6 +1882,17 @@ class PublicIpRange:
         [setattr(cmd, k, v) for k, v in kwargs.items()]
         return(apiclient.listVlanIpRanges(cmd))
 
+    @classmethod
+    def dedicate(cls, apiclient, id, zoneid, 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
+        cmd.zoneid = zoneid
+        return PublicIpRange(apiclient.dedicatePublicIpRange(cmd).__dict__)
 
 class SecondaryStorage:
     """Manage Secondary storage"""


[2/2] git commit: updated refs/heads/master to bf72a36

Posted by je...@apache.org.
CLOUDSTACK-1974: cloudstack UI - Infrastructure menu - zone detail - public traffic type - IP Ranges tab - add new action "Release from account", "Add Account" for existing IP Ranges.


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

Branch: refs/heads/master
Commit: bf72a36ea809ec0f9b354bf6a72dd2a09e1fcf6f
Parents: d6ed8d7
Author: Jessica Wang <je...@citrix.com>
Authored: Mon Apr 8 14:39:18 2013 -0700
Committer: Jessica Wang <je...@citrix.com>
Committed: Mon Apr 8 14:46:23 2013 -0700

----------------------------------------------------------------------
 ui/scripts/system.js |   78 ++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 77 insertions(+), 1 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/bf72a36e/ui/scripts/system.js
----------------------------------------------------------------------
diff --git a/ui/scripts/system.js b/ui/scripts/system.js
index 8d08584..d89f6b6 100644
--- a/ui/scripts/system.js
+++ b/ui/scripts/system.js
@@ -588,7 +588,83 @@
                             }
                           });
                         }
-                      }
+                      },
+											/*
+											releaseFromAccount: {
+                        label: 'Release from Account',
+                        action: function(args) {
+                          $.ajax({
+                            url: createURL('releasePublicIpRange'),
+                            data: {
+														  id: args.context.multiRule[0].id
+														},                            
+                            success: function(json) {
+                              args.response.success({
+                                notification: {
+                                  label: 'release from account',
+                                  poll: function(args) {
+                                    args.complete();
+                                  }
+                                }
+                              });
+                            },
+                            error: function(json) {
+                              args.response.error(parseXMLHttpResponse(json));
+                            }
+                          });
+                        }
+                      },
+											addAccount: {
+											  label: 'Add Account',												
+												createForm: {
+													title: 'Add Account',
+													fields: {
+														account: { label: 'Account' },
+														domainid: {
+															label: 'Domain',															
+															select: function(args) {
+																$.ajax({
+																	url: createURL('listDomains'),
+																	data: { listAll: true },
+																	success: function(json) {
+																		args.response.success({
+																			data: $.map(json.listdomainsresponse.domain, function(domain) {
+																				return {
+																					id: domain.id,
+																					description: domain.path
+																				};
+																			})
+																		});
+																	}
+																});
+															}
+														}
+													}
+												},												
+												action: function(args) {                          							
+												  var data = {
+														id: args.context.multiRule[0].id
+													};												
+                          $.ajax({
+                            url: createURL('dedicatePublicIpRange'),
+                            data: data,                        
+                            success: function(json) {
+                              args.response.success({
+                                notification: {
+                                  label: 'Add Account',
+                                  poll: function(args) {
+                                    args.complete();
+                                  }
+                                }
+                              });
+                            },
+                            error: function(json) {
+                              args.response.error(parseXMLHttpResponse(json));
+                            }
+                          });
+                        }
+											}
+											*/
                     },
                     dataProvider: function(args) {
                       $.ajax({