This is an automated email from the ASF dual-hosted git repository.

nvazquez pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/main by this push:
     new 34bd922  New API endpoint to update pod management network IP range 
(#5458)
34bd922 is described below

commit 34bd92259acd48a7735c032adc372df6cdc64cc4
Author: sureshanaparti <[email protected]>
AuthorDate: Tue Sep 21 02:49:05 2021 +0530

    New API endpoint to update pod management network IP range (#5458)
    
    * Add UpdatePodManagementNetwork api endpoint
    
    * Checkstyle changes and added a few methods
    
    * Minor Checkstyle change
    
    * Refactor UpdatePodManagementNetworkIpRangeCmd.java
    
    * Added missing parameters
    
    * Cleanup
    
    * Addressed the review comments
    
    Co-authored-by: kioie <[email protected]>
    Co-authored-by: kioie <[email protected]>
---
 .../cloud/configuration/ConfigurationService.java  |   9 ++
 api/src/main/java/com/cloud/event/EventTypes.java  |   1 +
 .../org/apache/cloudstack/api/ApiConstants.java    |   4 +
 .../UpdatePodManagementNetworkIpRangeCmd.java      | 154 ++++++++++++++++++
 .../com/cloud/dc/dao/DataCenterIpAddressDao.java   |   2 +
 .../cloud/dc/dao/DataCenterIpAddressDaoImpl.java   |  12 +-
 .../configuration/ConfigurationManagerImpl.java    | 173 +++++++++++++++++++++
 .../com/cloud/server/ManagementServerImpl.java     |   2 +
 .../cloud/vpc/MockConfigurationManagerImpl.java    |   9 ++
 9 files changed, 365 insertions(+), 1 deletion(-)

diff --git 
a/api/src/main/java/com/cloud/configuration/ConfigurationService.java 
b/api/src/main/java/com/cloud/configuration/ConfigurationService.java
index 6a51f7e..38d9d32 100644
--- a/api/src/main/java/com/cloud/configuration/ConfigurationService.java
+++ b/api/src/main/java/com/cloud/configuration/ConfigurationService.java
@@ -24,6 +24,7 @@ import 
org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd;
 import 
org.apache.cloudstack.api.command.admin.network.DeleteManagementNetworkIpRangeCmd;
 import 
org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd;
 import 
org.apache.cloudstack.api.command.admin.network.UpdateNetworkOfferingCmd;
+import 
org.apache.cloudstack.api.command.admin.network.UpdatePodManagementNetworkIpRangeCmd;
 import org.apache.cloudstack.api.command.admin.offering.CreateDiskOfferingCmd;
 import 
org.apache.cloudstack.api.command.admin.offering.CreateServiceOfferingCmd;
 import org.apache.cloudstack.api.command.admin.offering.DeleteDiskOfferingCmd;
@@ -205,6 +206,14 @@ public interface ConfigurationService {
     void deletePodIpRange(DeleteManagementNetworkIpRangeCmd cmd) throws 
ResourceUnavailableException, ConcurrentOperationException;
 
     /**
+     * Updates a mutually exclusive IP range in the pod.
+     * @param cmd - The command specifying pod ID, current Start IP, current 
End IP, new Start IP, new End IP.
+     * @throws com.cloud.exception.ConcurrentOperationException
+     * @return Success
+     */
+    void updatePodIpRange(UpdatePodManagementNetworkIpRangeCmd cmd) throws 
ConcurrentOperationException;
+
+    /**
      * Edits a pod in the database. Will not allow you to edit pods that are 
being used anywhere in the system.
      *
      * @param UpdatePodCmd
diff --git a/api/src/main/java/com/cloud/event/EventTypes.java 
b/api/src/main/java/com/cloud/event/EventTypes.java
index 808a868..c74a28f 100644
--- a/api/src/main/java/com/cloud/event/EventTypes.java
+++ b/api/src/main/java/com/cloud/event/EventTypes.java
@@ -328,6 +328,7 @@ public class EventTypes {
 
     public static final String EVENT_MANAGEMENT_IP_RANGE_CREATE = 
"MANAGEMENT.IP.RANGE.CREATE";
     public static final String EVENT_MANAGEMENT_IP_RANGE_DELETE = 
"MANAGEMENT.IP.RANGE.DELETE";
+    public static final String EVENT_MANAGEMENT_IP_RANGE_UPDATE = 
"MANAGEMENT.IP.RANGE.UPDATE";
 
     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";
diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java 
b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
index fd0dc78..0fff4ef 100644
--- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
@@ -98,6 +98,8 @@ public class ApiConstants {
     public static final String CUSTOMIZED_IOPS = "customizediops";
     public static final String CUSTOM_ID = "customid";
     public static final String CUSTOM_JOB_ID = "customjobid";
+    public static final String CURRENT_START_IP = "currentstartip";
+    public static final String CURRENT_END_IP = "currentendip";
     public static final String MIN_IOPS = "miniops";
     public static final String MAX_IOPS = "maxiops";
     public static final String HYPERVISOR_SNAPSHOT_RESERVE = 
"hypervisorsnapshotreserve";
@@ -252,6 +254,8 @@ public class ApiConstants {
     public static final String NIC = "nic";
     public static final String NIC_NETWORK_LIST = "nicnetworklist";
     public static final String NIC_IP_ADDRESS_LIST = "nicipaddresslist";
+    public static final String NEW_START_IP = "newstartip";
+    public static final String NEW_END_IP = "newendip";
     public static final String NUM_RETRIES = "numretries";
     public static final String OFFER_HA = "offerha";
     public static final String IS_SYSTEM_OFFERING = "issystem";
diff --git 
a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/UpdatePodManagementNetworkIpRangeCmd.java
 
b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/UpdatePodManagementNetworkIpRangeCmd.java
new file mode 100644
index 0000000..ee59631
--- /dev/null
+++ 
b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/UpdatePodManagementNetworkIpRangeCmd.java
@@ -0,0 +1,154 @@
+// 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.network;
+
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiArgValidator;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.PodResponse;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import org.apache.log4j.Logger;
+
+import com.cloud.event.EventTypes;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.user.Account;
+
+@APICommand(name = UpdatePodManagementNetworkIpRangeCmd.APINAME,
+        description = "Updates a management network IP range. Only allowed 
when no IPs are allocated.",
+        responseObject = SuccessResponse.class,
+        since = "4.16.0.0",
+        requestHasSensitiveInfo = false,
+        responseHasSensitiveInfo = false,
+        authorized = {RoleType.Admin})
+public class UpdatePodManagementNetworkIpRangeCmd extends BaseAsyncCmd {
+
+    public static final Logger s_logger = 
Logger.getLogger(UpdatePodManagementNetworkIpRangeCmd.class);
+
+    public static final String APINAME = "updatePodManagementNetworkIpRange";
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+    @Parameter(name = ApiConstants.POD_ID,
+            type = CommandType.UUID,
+            entityType = PodResponse.class,
+            required = true,
+            description = "UUID of POD, where the IP range belongs to.",
+            validations = {ApiArgValidator.PositiveNumber})
+    private Long podId;
+
+    @Parameter(name = ApiConstants.CURRENT_START_IP,
+            type = CommandType.STRING,
+            entityType = PodResponse.class,
+            required = true,
+            description = "The current starting IP address.",
+            validations = {ApiArgValidator.NotNullOrEmpty})
+    private String currentStartIp;
+
+    @Parameter(name = ApiConstants.CURRENT_END_IP,
+            type = CommandType.STRING,
+            entityType = PodResponse.class,
+            required = true,
+            description = "The current ending IP address.",
+            validations = {ApiArgValidator.NotNullOrEmpty})
+    private String currentEndIp;
+
+    @Parameter(name = ApiConstants.NEW_START_IP,
+            type = CommandType.STRING,
+            description = "The new starting IP address.",
+            validations = {ApiArgValidator.NotNullOrEmpty})
+    private String newStartIp;
+
+    @Parameter(name = ApiConstants.NEW_END_IP,
+            type = CommandType.STRING,
+            description = "The new ending IP address.",
+            validations = {ApiArgValidator.NotNullOrEmpty})
+    private String newEndIp;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getPodId() {
+        return podId;
+    }
+
+    public String getCurrentStartIP() {
+        return currentStartIp;
+    }
+
+    public String getCurrentEndIP() {
+        return currentEndIp;
+    }
+
+    public String getNewStartIP() {
+        return newStartIp;
+    }
+
+    public String getNewEndIP() {
+        return newEndIp;
+    }
+
+    @Override
+    public String getEventType() {
+        return EventTypes.EVENT_MANAGEMENT_IP_RANGE_UPDATE;
+    }
+
+    @Override
+    public String getEventDescription() {
+        return "Updating pod management IP range " + getNewStartIP() + "-" + 
getNewEndIP() + " of Pod: " + getPodId();
+    }
+
+    @Override
+    public String getCommandName() {
+        return APINAME.toLowerCase() + BaseAsyncCmd.RESPONSE_SUFFIX;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return Account.ACCOUNT_ID_SYSTEM;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public void execute() {
+        if (getNewStartIP() == null && getNewEndIP() == null) {
+            throw new InvalidParameterValueException("Either new starting IP 
address or new ending IP address must be specified");
+        }
+
+        try {
+            _configService.updatePodIpRange(this);
+            SuccessResponse response = new SuccessResponse(getCommandName());
+            this.setResponseObject(response);
+        } catch (ConcurrentOperationException ex) {
+            s_logger.warn("Exception: ", ex);
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, 
ex.getMessage());
+        } catch (Exception e) {
+            s_logger.warn("Failed to update pod management IP range " + 
getNewStartIP() + "-" + getNewEndIP() + " of Pod: " + getPodId(), e);
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, 
e.getMessage());
+        }
+    }
+}
diff --git 
a/engine/schema/src/main/java/com/cloud/dc/dao/DataCenterIpAddressDao.java 
b/engine/schema/src/main/java/com/cloud/dc/dao/DataCenterIpAddressDao.java
index bb840b5..2c65539 100644
--- a/engine/schema/src/main/java/com/cloud/dc/dao/DataCenterIpAddressDao.java
+++ b/engine/schema/src/main/java/com/cloud/dc/dao/DataCenterIpAddressDao.java
@@ -41,6 +41,8 @@ public interface DataCenterIpAddressDao extends 
GenericDao<DataCenterIpAddressVO
 
     List<DataCenterIpAddressVO> listByPodIdDcId(long podId, long dcId);
 
+    List<DataCenterIpAddressVO> listIpAddressUsage(final long podId, final 
long dcId, final boolean onlyListAllocated);
+
     int countIPs(long podId, long dcId, boolean onlyCountAllocated);
 
     int countIPs(long dcId, boolean onlyCountAllocated);
diff --git 
a/engine/schema/src/main/java/com/cloud/dc/dao/DataCenterIpAddressDaoImpl.java 
b/engine/schema/src/main/java/com/cloud/dc/dao/DataCenterIpAddressDaoImpl.java
index 8b0a44b..e58b08d 100644
--- 
a/engine/schema/src/main/java/com/cloud/dc/dao/DataCenterIpAddressDaoImpl.java
+++ 
b/engine/schema/src/main/java/com/cloud/dc/dao/DataCenterIpAddressDaoImpl.java
@@ -21,7 +21,6 @@ import java.sql.SQLException;
 import java.util.Date;
 import java.util.List;
 
-
 import org.apache.cloudstack.framework.config.ConfigKey;
 import org.apache.cloudstack.framework.config.Configurable;
 import org.apache.log4j.Logger;
@@ -239,6 +238,17 @@ public class DataCenterIpAddressDaoImpl extends 
GenericDaoBase<DataCenterIpAddre
     }
 
     @Override
+    public List<DataCenterIpAddressVO> listIpAddressUsage(final long podId, 
final long dcId, final boolean onlyListAllocated) {
+        SearchCriteria<DataCenterIpAddressVO> sc = createSearchCriteria();
+        if(onlyListAllocated) {
+            sc.addAnd("takenAt", SearchCriteria.Op.NNULL);
+        }
+        sc.addAnd("podId", SearchCriteria.Op.EQ, podId);
+        sc.addAnd("dataCenterId", SearchCriteria.Op.EQ, dcId);
+        return listBy(sc);
+    }
+
+    @Override
     public List<DataCenterIpAddressVO> listByPodIdDcIdIpAddress(long podId, 
long dcId, String ipAddress) {
         SearchCriteria<DataCenterIpAddressVO> sc = AllFieldsSearch.create();
         sc.setParameters("pod", podId);
diff --git 
a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java 
b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
index 5a0a34b..4e9828a 100755
--- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -57,6 +57,7 @@ import 
org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd;
 import 
org.apache.cloudstack.api.command.admin.network.DeleteManagementNetworkIpRangeCmd;
 import 
org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd;
 import 
org.apache.cloudstack.api.command.admin.network.UpdateNetworkOfferingCmd;
+import 
org.apache.cloudstack.api.command.admin.network.UpdatePodManagementNetworkIpRangeCmd;
 import org.apache.cloudstack.api.command.admin.offering.CreateDiskOfferingCmd;
 import 
org.apache.cloudstack.api.command.admin.offering.CreateServiceOfferingCmd;
 import org.apache.cloudstack.api.command.admin.offering.DeleteDiskOfferingCmd;
@@ -1531,6 +1532,178 @@ public class ConfigurationManagerImpl extends 
ManagerBase implements Configurati
     }
 
     @Override
+    @DB
+    public void updatePodIpRange(final UpdatePodManagementNetworkIpRangeCmd 
cmd) throws ConcurrentOperationException {
+        final long podId = cmd.getPodId();
+        final HostPodVO pod = _podDao.findById(podId);
+        if (pod == null) {
+            throw new InvalidParameterValueException("Unable to find pod by 
id: " + podId);
+        }
+
+        final String currentStartIP = cmd.getCurrentStartIP();
+        final String currentEndIP = cmd.getCurrentEndIP();
+        String newStartIP = cmd.getNewStartIP();
+        String newEndIP = cmd.getNewEndIP();
+
+        if (newStartIP == null) {
+            newStartIP = currentStartIP;
+        }
+
+        if (newEndIP == null) {
+            newEndIP = currentEndIP;
+        }
+
+        if (newStartIP.equals(currentStartIP) && 
newEndIP.equals(currentEndIP)) {
+            throw new InvalidParameterValueException("New starting and ending 
IP address are the same as current starting and ending IP address");
+        }
+
+        final String[] existingPodIpRanges = pod.getDescription().split(",");
+        if (existingPodIpRanges.length == 0) {
+            throw new InvalidParameterValueException("The IP range cannot be 
found in the pod: " + podId + " since the existing IP range is empty.");
+        }
+
+        verifyIpRangeParameters(currentStartIP,currentEndIP);
+        verifyIpRangeParameters(newStartIP,newEndIP);
+        
checkIpRangeContainsTakenAddresses(pod,currentStartIP,currentEndIP,newStartIP,newEndIP);
+
+        String vlan = 
verifyPodIpRangeExists(podId,existingPodIpRanges,currentStartIP,currentEndIP,newStartIP,newEndIP);
+
+        List<Long> currentIpRange = 
listAllIPsWithintheRange(currentStartIP,currentEndIP);
+        List<Long> newIpRange = listAllIPsWithintheRange(newStartIP,newEndIP);
+
+        try {
+            final String finalNewEndIP = newEndIP;
+            final String finalNewStartIP = newStartIP;
+            final Integer vlanId = vlan.equals(Vlan.UNTAGGED) ? null : 
Integer.parseInt(vlan);
+
+            Transaction.execute(new TransactionCallbackNoReturn() {
+                @Override
+                public void doInTransactionWithoutResult(final 
TransactionStatus status) {
+                    final long zoneId = pod.getDataCenterId();
+                    
pod.setDescription(pod.getDescription().replace(currentStartIP + "-",
+                            finalNewStartIP + "-").replace(currentEndIP, 
finalNewEndIP));
+                    
updatePodIpRangeInDb(zoneId,podId,vlanId,pod,newIpRange,currentIpRange);
+                }
+            });
+        } catch (final Exception e) {
+            s_logger.error("Unable to update Pod " + podId + " IP range due to 
" + e.getMessage(), e);
+            throw new CloudRuntimeException("Failed to update Pod " + podId + 
" IP range. Please contact Cloud Support.");
+        }
+    }
+
+    private String verifyPodIpRangeExists(long podId,String[] 
existingPodIpRanges, String currentStartIP,
+            String currentEndIP, String newStartIP, String newEndIP) {
+        boolean foundRange = false;
+        String vlan = null;
+
+        for (String podIpRange: existingPodIpRanges) {
+            final String[] existingPodIpRange = podIpRange.split("-");
+
+            if (existingPodIpRange.length > 1) {
+                if (!NetUtils.isValidIp4(existingPodIpRange[0]) || 
!NetUtils.isValidIp4(existingPodIpRange[1])) {
+                    continue;
+                }
+                if (currentStartIP.equals(existingPodIpRange[0]) && 
currentEndIP.equals(existingPodIpRange[1])) {
+                    foundRange = true;
+                    vlan = existingPodIpRange[3];
+                }
+                if (!foundRange && NetUtils.ipRangesOverlap(newStartIP, 
newEndIP, existingPodIpRange[0], existingPodIpRange[1])) {
+                    throw new InvalidParameterValueException("The Start and 
End IP address range: (" + newStartIP + "-" + newEndIP + ") overlap with the 
pod IP range: " + podIpRange);
+                }
+            }
+        }
+
+        if (!foundRange) {
+            throw new InvalidParameterValueException("The input IP range: " + 
currentStartIP + "-" + currentEndIP + " of pod: " + podId + " is not present. 
Please input an existing range.");
+        }
+
+        return vlan;
+    }
+
+    private void updatePodIpRangeInDb (long zoneId, long podId, Integer 
vlanId, HostPodVO pod, List<Long> newIpRange, List<Long> currentIpRange) {
+        HostPodVO lock = null;
+        try {
+            lock = _podDao.acquireInLockTable(podId);
+            if (lock == null) {
+                String msg = "Unable to acquire lock on table to update the ip 
range of POD: " + pod.getName() + ", Update failed.";
+                s_logger.warn(msg);
+                throw new CloudRuntimeException(msg);
+            }
+            List<Long> iPaddressesToAdd = new ArrayList(newIpRange);
+            iPaddressesToAdd.removeAll(currentIpRange);
+            if (iPaddressesToAdd.size() > 0) {
+                for (Long startIP : iPaddressesToAdd) {
+                    _zoneDao.addPrivateIpAddress(zoneId, podId, 
NetUtils.long2Ip(startIP), NetUtils.long2Ip(startIP), false, vlanId);
+                }
+            } else {
+                currentIpRange.removeAll(newIpRange);
+                if (currentIpRange.size() > 0) {
+                    for (Long startIP: currentIpRange) {
+                        if 
(!_privateIpAddressDao.deleteIpAddressByPodDc(NetUtils.long2Ip(startIP),podId,zoneId))
 {
+                            throw new CloudRuntimeException("Failed to remove 
private ip address: " + NetUtils.long2Ip(startIP) + " of Pod: " + podId + " DC: 
" + pod.getDataCenterId());
+                        }
+                    }
+                }
+            }
+            _podDao.update(podId, pod);
+        } catch (final Exception e) {
+            s_logger.error("Unable to update Pod " + podId + " IP range due to 
database error " + e.getMessage(), e);
+            throw new CloudRuntimeException("Failed to update Pod " + podId + 
" IP range. Please contact Cloud Support.");
+        }  finally {
+            if (lock != null) {
+                _podDao.releaseFromLockTable(podId);
+            }
+        }
+    }
+
+    private List<Long> listAllIPsWithintheRange(String startIp, String endIP) {
+        verifyIpRangeParameters(startIp,endIP);
+        long startIpLong = NetUtils.ip2Long(startIp);
+        long endIpLong = NetUtils.ip2Long(endIP);
+
+        List<Long> listOfIpsinRange = new ArrayList<>();
+        while (startIpLong <= endIpLong) {
+            listOfIpsinRange.add(startIpLong);
+            startIpLong++;
+        }
+        return listOfIpsinRange;
+    }
+
+    private void verifyIpRangeParameters(String startIP, String endIp) {
+
+        if (!Strings.isNullOrEmpty(startIP) && !NetUtils.isValidIp4(startIP)) {
+            throw new InvalidParameterValueException("The current start 
address of the IP range " + startIP + " is not a valid IP address.");
+        }
+
+        if (!Strings.isNullOrEmpty(endIp) && !NetUtils.isValidIp4(endIp)) {
+            throw new InvalidParameterValueException("The current end address 
of the IP range " + endIp + " is not a valid IP address.");
+        }
+
+        if (NetUtils.ip2Long(startIP) > NetUtils.ip2Long(endIp)) {
+            throw new InvalidParameterValueException("The start IP address 
must have a lower value than the end IP address.");
+        }
+    }
+
+    private void checkIpRangeContainsTakenAddresses(final HostPodVO pod,final 
String currentStartIP,
+            final String currentEndIP,final String newStartIp, final String 
newEndIp) {
+
+        List<Long> newIpRange = listAllIPsWithintheRange(newStartIp,newEndIp);
+        List<Long> currentIpRange = 
listAllIPsWithintheRange(currentStartIP,currentEndIP);
+        List<Long> takenIpsList = new ArrayList<>();
+        final List<DataCenterIpAddressVO> takenIps = 
_privateIpAddressDao.listIpAddressUsage(pod.getId(),pod.getDataCenterId(),true);
+
+        for (DataCenterIpAddressVO takenIp : takenIps) {
+            takenIpsList.add(NetUtils.ip2Long(takenIp.getIpAddress()));
+        }
+
+        takenIpsList.retainAll(currentIpRange);
+        if (!newIpRange.containsAll(takenIpsList)) {
+            throw new InvalidParameterValueException("The IP range does not 
contain some IP addresses that have "
+                    + "already been taken. Please adjust your IP range to 
include all IP addresses already taken.");
+        }
+    }
+
+    @Override
     public Pod editPod(final UpdatePodCmd cmd) {
         return editPod(cmd.getId(), cmd.getPodName(), null, null, 
cmd.getGateway(), cmd.getNetmask(), cmd.getAllocationState());
     }
diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java 
b/server/src/main/java/com/cloud/server/ManagementServerImpl.java
index 075b338..e0db746 100644
--- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java
@@ -148,6 +148,7 @@ import 
org.apache.cloudstack.api.command.admin.network.UpdateNetworkCmdByAdmin;
 import 
org.apache.cloudstack.api.command.admin.network.UpdateNetworkOfferingCmd;
 import 
org.apache.cloudstack.api.command.admin.network.UpdateNetworkServiceProviderCmd;
 import 
org.apache.cloudstack.api.command.admin.network.UpdatePhysicalNetworkCmd;
+import 
org.apache.cloudstack.api.command.admin.network.UpdatePodManagementNetworkIpRangeCmd;
 import 
org.apache.cloudstack.api.command.admin.network.UpdateStorageNetworkIpRangeCmd;
 import org.apache.cloudstack.api.command.admin.offering.CreateDiskOfferingCmd;
 import 
org.apache.cloudstack.api.command.admin.offering.CreateServiceOfferingCmd;
@@ -3052,6 +3053,7 @@ public class ManagementServerImpl extends ManagerBase 
implements ManagementServe
         cmdList.add(UpdateRegionCmd.class);
         cmdList.add(ListAlertsCmd.class);
         cmdList.add(ListCapacityCmd.class);
+        cmdList.add(UpdatePodManagementNetworkIpRangeCmd.class);
         cmdList.add(UploadCustomCertificateCmd.class);
         cmdList.add(ConfigureVirtualRouterElementCmd.class);
         cmdList.add(CreateVirtualRouterElementCmd.class);
diff --git 
a/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java 
b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java
index d6dbee8..112d20b 100644
--- a/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java
+++ b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java
@@ -29,6 +29,7 @@ import 
org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd;
 import 
org.apache.cloudstack.api.command.admin.network.DeleteManagementNetworkIpRangeCmd;
 import 
org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd;
 import 
org.apache.cloudstack.api.command.admin.network.UpdateNetworkOfferingCmd;
+import 
org.apache.cloudstack.api.command.admin.network.UpdatePodManagementNetworkIpRangeCmd;
 import org.apache.cloudstack.api.command.admin.offering.CreateDiskOfferingCmd;
 import 
org.apache.cloudstack.api.command.admin.offering.CreateServiceOfferingCmd;
 import org.apache.cloudstack.api.command.admin.offering.DeleteDiskOfferingCmd;
@@ -205,6 +206,14 @@ public class MockConfigurationManagerImpl extends 
ManagerBase implements Configu
     }
 
     /* (non-Javadoc)
+     * @see 
com.cloud.configuration.ConfigurationService#updatePodIpRange(org.apache.cloudstack.api.command.admin.network.UpdatePodManagementNetworkIpRangeCmd)
+     */
+    public void updatePodIpRange(final UpdatePodManagementNetworkIpRangeCmd 
cmd) throws ConcurrentOperationException {
+        // TODO Auto-generated method stub
+        return;
+    }
+
+    /* (non-Javadoc)
      * @see 
com.cloud.configuration.ConfigurationService#editPod(org.apache.cloudstack.api.commands.UpdatePodCmd)
      */
     @Override

Reply via email to