You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by GitBox <gi...@apache.org> on 2021/09/15 08:12:33 UTC

[GitHub] [cloudstack] DaanHoogland commented on a change in pull request #5411: Add New API endpoint: UpdateVlanIpRange

DaanHoogland commented on a change in pull request #5411:
URL: https://github.com/apache/cloudstack/pull/5411#discussion_r708942078



##########
File path: server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
##########
@@ -4569,6 +4847,59 @@ protected boolean savePublicIPRange(final String startIP, final String endIP, fi
         return problemIps != null && problemIps.size() == 0;
     }
 
+    @DB
+    protected boolean updatePublicIPRange(final String newStartIP, final String currentStartIP, final String newEndIP, final String currentEndIP, final long zoneId, final long vlanDbId, final long sourceNetworkid, final long physicalNetworkId, final boolean isRangeForSystemVM, final Boolean forSystemVms) {

Review comment:
       can you here make a javadoc with what a `true` or `false` return value mean and what the side effects are in terms of DB contents?

##########
File path: server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
##########
@@ -4237,6 +4246,274 @@ public VlanVO doInTransaction(final TransactionStatus status) {
 
     }
 
+    @Override
+    public Vlan updateVlanAndPublicIpRange(UpdateVlanIpRangeCmd cmd) throws ConcurrentOperationException,
+            ResourceUnavailableException,ResourceAllocationException {
+
+        return  updateVlanAndPublicIpRange(cmd.getId(), cmd.getStartIp(),cmd.getEndIp(), cmd.getGateway(),cmd.getNetmask(),
+                cmd.getStartIpv6(), cmd.getEndIpv6(), cmd.getIp6Gateway(), cmd.getIp6Cidr(), cmd.isForSystemVms());
+    }
+
+    @DB
+    @ActionEvent(eventType = EventTypes.EVENT_VLAN_IP_RANGE_UPDATE, eventDescription = "update vlan ip Range", async
+            = false)
+    public Vlan updateVlanAndPublicIpRange(final long id, String startIp,

Review comment:
       this is a 160 lines method. can you modularise it a bit more, please?

##########
File path: api/src/main/java/com/cloud/configuration/ConfigurationService.java
##########
@@ -272,6 +273,16 @@
     Vlan createVlanAndPublicIpRange(CreateVlanIpRangeCmd cmd) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException,
         ResourceAllocationException;
 
+    /**
+     * Updates the IP address Range for the VLAN on the database
+     * @param cmd
+     * @return The Updated Vlan Object
+     * @throws ConcurrentOperationException
+     * @throws ResourceUnavailableException
+     * @throws ResourceAllocationException

Review comment:
       except for the `@return` these annotation don;t provide extra info and we might as well delete those.

##########
File path: server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
##########
@@ -4237,6 +4246,274 @@ public VlanVO doInTransaction(final TransactionStatus status) {
 
     }
 
+    @Override
+    public Vlan updateVlanAndPublicIpRange(UpdateVlanIpRangeCmd cmd) throws ConcurrentOperationException,
+            ResourceUnavailableException,ResourceAllocationException {
+
+        return  updateVlanAndPublicIpRange(cmd.getId(), cmd.getStartIp(),cmd.getEndIp(), cmd.getGateway(),cmd.getNetmask(),
+                cmd.getStartIpv6(), cmd.getEndIpv6(), cmd.getIp6Gateway(), cmd.getIp6Cidr(), cmd.isForSystemVms());
+    }
+
+    @DB
+    @ActionEvent(eventType = EventTypes.EVENT_VLAN_IP_RANGE_UPDATE, eventDescription = "update vlan ip Range", async
+            = false)
+    public Vlan updateVlanAndPublicIpRange(final long id, String startIp,
+                                           String endIp,
+                                           String gateway,
+                                           String netmask,
+                                           String startIpv6,
+                                           String endIpv6,
+                                           String ip6Gateway,
+                                           String ip6Cidr,
+                                           Boolean forSystemVms) throws ConcurrentOperationException {
+
+        VlanVO vlanRange = _vlanDao.findById(id);
+        if (vlanRange == null) {
+            throw new InvalidParameterValueException("Please specify a valid IP range id.");
+        }
+
+        final boolean ipv4 = vlanRange.getVlanGateway() != null;
+        final boolean ipv6 = vlanRange.getIp6Gateway() != null;
+        if (!ipv4) {
+            if (startIp != null || endIp != null || gateway != null || netmask != null) {
+                throw new InvalidParameterValueException("IPv4 is not support in this IP range.");
+            }
+        }
+        if (!ipv6) {
+            if (startIpv6 != null || endIpv6 != null || ip6Gateway != null || ip6Cidr != null) {
+                throw new InvalidParameterValueException("IPv6 is not support in this IP range.");
+            }
+        }
+
+        final Boolean isRangeForSystemVM = checkIfVlanRangeIsForSystemVM(id);
+        if (forSystemVms != null && isRangeForSystemVM != forSystemVms) {
+            if (VlanType.DirectAttached.equals(vlanRange.getVlanType())) {
+                throw new InvalidParameterValueException("forSystemVms is not available for this IP range with vlan type: " + VlanType.DirectAttached);
+            }
+            // Check if range has already been dedicated
+            final List<AccountVlanMapVO> maps = _accountVlanMapDao.listAccountVlanMapsByVlan(id);
+            if (maps != null && !maps.isEmpty()) {
+                throw new InvalidParameterValueException("Specified Public IP range has already been dedicated to an account");
+            }
+
+            List<DomainVlanMapVO> domainmaps = _domainVlanMapDao.listDomainVlanMapsByVlan(id);
+            if (domainmaps != null && !domainmaps.isEmpty()) {
+                throw new InvalidParameterValueException("Specified Public IP range has already been dedicated to a domain");
+            }
+        }
+        if (ipv4) {
+            if (gateway != null && !gateway.equals(vlanRange.getVlanGateway())) {
+                throw new InvalidParameterValueException("The input gateway " + gateway + " is not same as IP range gateway " + vlanRange.getVlanGateway());
+            }
+            if (netmask != null && !netmask.equals(vlanRange.getVlanNetmask())) {
+                throw new InvalidParameterValueException("The input netmask " + netmask + " is not same as IP range netmask " + vlanRange.getVlanNetmask());
+            }
+
+            if (gateway == null) {
+                gateway = vlanRange.getVlanGateway();
+            }
+
+            if (netmask == null) {
+                netmask = vlanRange.getVlanNetmask();
+            }
+
+            final String[] existingVlanIPRangeArray = vlanRange.getIpRange().split("-");
+            final String currentStartIP = existingVlanIPRangeArray[0];
+            final String currentEndIP = existingVlanIPRangeArray[1];
+
+            if (startIp == null) {
+                startIp = currentStartIP;
+            }
+
+            if (endIp == null) {
+                endIp = currentEndIP;
+            }
+
+            final String cidr = NetUtils.ipAndNetMaskToCidr(gateway, netmask);
+            if (Strings.isNullOrEmpty(cidr)) {
+                throw new InvalidParameterValueException(String.format("Invalid gateway (%s) or netmask (%s)", gateway, netmask));
+            }
+            final String cidrAddress = getCidrAddress(cidr);
+            final long cidrSize = getCidrSize(cidr);
+
+            checkIpRange(currentStartIP, currentEndIP, cidrAddress, cidrSize);
+            if (startIp != currentStartIP || endIp != currentEndIP) {
+                checkIpRange(startIp, endIp, cidrAddress, cidrSize);
+            }
+
+            checkGatewayOverlap(startIp, endIp, gateway);
+
+            final List<IPAddressVO> ips = _publicIpAddressDao.listByVlanId(id);
+            checkAllocatedIpsAreWithinVlanRange(ips, startIp, endIp, forSystemVms);
+
+            try {
+                final String newStartIP = startIp;
+                final String newEndIP = endIp;
+
+                VlanVO range = _vlanDao.acquireInLockTable(id, 30);
+                if (range == null) {
+                    throw new CloudRuntimeException("Unable to acquire vlan configuration: " + id);
+                }
+
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug("lock vlan " + id + " is acquired");
+                }
+
+                commitUpdateVlanAndIpRange(id, newStartIP, newEndIP, currentStartIP, currentEndIP, true, isRangeForSystemVM, forSystemVms);
+
+            } catch (final Exception e) {
+                s_logger.error("Unable to edit VlanRange due to " + e.getMessage(), e);
+                throw new CloudRuntimeException("Failed to edit VlanRange. Please contact Cloud Support.");
+            } finally {
+                _vlanDao.releaseFromLockTable(id);
+            }
+        }
+
+        if (ipv6) {
+            if (ip6Gateway != null && !ip6Gateway.equals(vlanRange.getIp6Gateway())) {
+                throw new InvalidParameterValueException("The input gateway " + ip6Gateway + " is not same as IP range gateway " + vlanRange.getIp6Gateway());
+            }
+            if (ip6Cidr != null && !ip6Cidr.equals(vlanRange.getIp6Cidr())) {
+                throw new InvalidParameterValueException("The input cidr " + ip6Cidr + " is not same as IP range cidr " + vlanRange.getIp6Cidr());
+            }
+            ip6Gateway = MoreObjects.firstNonNull(ip6Gateway, vlanRange.getIp6Gateway());
+            ip6Cidr = MoreObjects.firstNonNull(ip6Cidr, vlanRange.getIp6Cidr());
+
+            final String[] existingVlanIPRangeArray = vlanRange.getIp6Range().split("-");
+            final String currentStartIPv6 = existingVlanIPRangeArray[0];
+            final String currentEndIPv6 = existingVlanIPRangeArray[1];
+
+            if (startIpv6 == null) {
+                startIpv6 = currentStartIPv6;
+            }
+            if (endIpv6 == null) {
+                endIpv6 = currentEndIPv6;
+            }
+            if (startIpv6 != currentStartIPv6 || endIpv6 != currentEndIPv6) {
+                _networkModel.checkIp6Parameters(startIpv6, endIpv6, ip6Gateway, ip6Cidr);
+                final List<UserIpv6AddressVO> ips = _ipv6Dao.listByVlanId(id);
+                checkAllocatedIpv6sAreWithinVlanRange(ips, startIp, endIp);
+
+                try {
+                    VlanVO range = _vlanDao.acquireInLockTable(id, 30);
+                    if (range == null) {
+                        throw new CloudRuntimeException("Unable to acquire vlan configuration: " + id);
+                    }
+
+                    if (s_logger.isDebugEnabled()) {
+                        s_logger.debug("lock vlan " + id + " is acquired");
+                    }
+
+                    commitUpdateVlanAndIpRange(id, startIpv6, endIpv6, currentStartIPv6, currentEndIPv6, false, isRangeForSystemVM,forSystemVms);
+
+                } catch (final Exception e) {
+                    s_logger.error("Unable to edit VlanRange due to " + e.getMessage(), e);
+                    throw new CloudRuntimeException("Failed to edit VlanRange. Please contact Cloud Support.");
+                } finally {
+                    _vlanDao.releaseFromLockTable(id);
+                }
+            }
+        }
+
+        return _vlanDao.findById(id);
+    }
+
+    private VlanVO commitUpdateVlanAndIpRange(final Long id, final String newStartIP, final String newEndIP, final String currentStartIP, final String currentEndIP,
+                                              final boolean ipv4, final Boolean isRangeForSystemVM, final Boolean forSystemvms) {
+
+        return Transaction.execute(new TransactionCallback<VlanVO>() {
+            @Override
+            public VlanVO doInTransaction(final TransactionStatus status) {
+                VlanVO vlanRange = _vlanDao.findById(id);
+                s_logger.debug("Updating vlan range " + vlanRange.getId());
+                if (ipv4) {
+                    vlanRange.setIpRange(newStartIP + "-" + newEndIP);
+                    _vlanDao.update(vlanRange.getId(), vlanRange);
+                    if (!updatePublicIPRange(newStartIP, currentStartIP, newEndIP, currentEndIP, vlanRange.getDataCenterId(), vlanRange.getId(), vlanRange.getNetworkId(), vlanRange.getPhysicalNetworkId(), isRangeForSystemVM, forSystemvms)) {
+                        throw new CloudRuntimeException("Failed to update IPv4 range. Please contact Cloud Support.");
+                    }
+                } else {
+                    vlanRange.setIp6Range(newStartIP + "-" + newEndIP);
+                    _vlanDao.update(vlanRange.getId(), vlanRange);
+                }
+                return vlanRange;
+            }
+        });
+    }
+
+    private boolean checkIfVlanRangeIsForSystemVM(final long vlanId) {
+        List<IPAddressVO> existingPublicIPs = _publicIpAddressDao.listByVlanId(vlanId);
+        boolean initialIsSystemVmValue = existingPublicIPs.get(0).isForSystemVms();
+        for (IPAddressVO existingIPs : existingPublicIPs) {
+            if (initialIsSystemVmValue != existingIPs.isForSystemVms()) {
+                throw new CloudRuntimeException("Your \"For System VM\" value seems to be inconsistent with the rest of the records. Please contact Cloud Support");
+            }
+        }
+        return initialIsSystemVmValue;
+    }
+
+    private void checkAllocatedIpsAreWithinVlanRange(List<IPAddressVO> ips, String startIp, String endIp, Boolean forSystemVms) {
+
+        List<IPAddressVO> listAllocatedIPs = new ArrayList<>();
+        for (final IPAddressVO ip : ips) {
+            if (ip.getState() == IpAddress.State.Allocated) {
+                listAllocatedIPs.add(ip);
+            }
+        }
+        Collections.sort(listAllocatedIPs, Comparator.comparing(IPAddressVO::getAddress));
+        for (IPAddressVO allocatedIP : listAllocatedIPs) {
+            if (!Strings.isNullOrEmpty(startIp) && NetUtils.ip2Long(startIp) > NetUtils.ip2Long(allocatedIP.getAddress().addr())) {
+                throw new InvalidParameterValueException("The start IP address must have a lower IP address value "
+                        + "than " + allocatedIP.getAddress() + " which is already in use. The end IP must have a "
+                        + "higher IP address than " + listAllocatedIPs.get(listAllocatedIPs.size() - 1).getAddress() + " .IPs "
+                        + "already allocated in this range: " + listAllocatedIPs.size());
+            }
+            if (!Strings.isNullOrEmpty(endIp) && NetUtils.ip2Long(endIp) < NetUtils.ip2Long(allocatedIP.getAddress().addr())) {
+                throw new InvalidParameterValueException("The start IP address must have a lower IP address value "
+                        + "than " + listAllocatedIPs.get(0).getAddress() + " which is already in use. The end IP must have a "
+                        + "higher IP address than " +  allocatedIP.getAddress() + " .IPs "
+                        + "already allocated in this range: " + listAllocatedIPs.size());
+            }
+            if (forSystemVms != null && allocatedIP.isForSystemVms() != forSystemVms) {
+                throw new InvalidParameterValueException(String.format("IP %s is in use, cannot change forSystemVms of the IP range", allocatedIP.getAddress().addr()));
+            }
+        }
+    }
+
+    private void checkAllocatedIpv6sAreWithinVlanRange(List<UserIpv6AddressVO> ips, String startIpv6, String endIpv6) {
+
+        List<UserIpv6AddressVO> listAllocatedIPs = new ArrayList<>();
+        for (final UserIpv6AddressVO ip : ips) {
+            if (ip.getState() == UserIpv6Address.State.Allocated) {
+                listAllocatedIPs.add(ip);
+            }
+        }
+        Collections.sort(listAllocatedIPs, Comparator.comparing(UserIpv6AddressVO::getAddress));
+        for (UserIpv6AddressVO allocatedIP : listAllocatedIPs) {
+            if (!Strings.isNullOrEmpty(startIpv6)
+                    && IPv6Address.fromString(startIpv6).toBigInteger().compareTo(IPv6Address.fromString(allocatedIP.getAddress()).toBigInteger()) > 0) {
+                throw new InvalidParameterValueException("The start IP address must have a lower IP address value "
+                        + "than " + allocatedIP.getAddress() + " which is already in use. The end IP must have a "
+                        + "higher IP address than " + listAllocatedIPs.get(listAllocatedIPs.size() - 1).getAddress() + " .IPs "
+                        + "already allocated in this range: " + listAllocatedIPs.size());
+            }
+            if (!Strings.isNullOrEmpty(endIpv6)
+                    && IPv6Address.fromString(endIpv6).toBigInteger().compareTo(IPv6Address.fromString(allocatedIP.getAddress()).toBigInteger()) < 0) {
+                throw new InvalidParameterValueException("The start IP address must have a lower IP address value "
+                        + "than " + listAllocatedIPs.get(0).getAddress() + " which is already in use. The end IP must have a "
+                        + "higher IP address than " +  allocatedIP.getAddress() + " .IPs "
+                        + "already allocated in this range: " + listAllocatedIPs.size());

Review comment:
       and this

##########
File path: server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
##########
@@ -4237,6 +4246,274 @@ public VlanVO doInTransaction(final TransactionStatus status) {
 
     }
 
+    @Override
+    public Vlan updateVlanAndPublicIpRange(UpdateVlanIpRangeCmd cmd) throws ConcurrentOperationException,
+            ResourceUnavailableException,ResourceAllocationException {
+
+        return  updateVlanAndPublicIpRange(cmd.getId(), cmd.getStartIp(),cmd.getEndIp(), cmd.getGateway(),cmd.getNetmask(),
+                cmd.getStartIpv6(), cmd.getEndIpv6(), cmd.getIp6Gateway(), cmd.getIp6Cidr(), cmd.isForSystemVms());
+    }
+
+    @DB
+    @ActionEvent(eventType = EventTypes.EVENT_VLAN_IP_RANGE_UPDATE, eventDescription = "update vlan ip Range", async
+            = false)
+    public Vlan updateVlanAndPublicIpRange(final long id, String startIp,
+                                           String endIp,
+                                           String gateway,
+                                           String netmask,
+                                           String startIpv6,
+                                           String endIpv6,
+                                           String ip6Gateway,
+                                           String ip6Cidr,
+                                           Boolean forSystemVms) throws ConcurrentOperationException {
+
+        VlanVO vlanRange = _vlanDao.findById(id);
+        if (vlanRange == null) {
+            throw new InvalidParameterValueException("Please specify a valid IP range id.");
+        }
+
+        final boolean ipv4 = vlanRange.getVlanGateway() != null;
+        final boolean ipv6 = vlanRange.getIp6Gateway() != null;
+        if (!ipv4) {
+            if (startIp != null || endIp != null || gateway != null || netmask != null) {
+                throw new InvalidParameterValueException("IPv4 is not support in this IP range.");
+            }
+        }
+        if (!ipv6) {
+            if (startIpv6 != null || endIpv6 != null || ip6Gateway != null || ip6Cidr != null) {
+                throw new InvalidParameterValueException("IPv6 is not support in this IP range.");
+            }
+        }
+
+        final Boolean isRangeForSystemVM = checkIfVlanRangeIsForSystemVM(id);
+        if (forSystemVms != null && isRangeForSystemVM != forSystemVms) {
+            if (VlanType.DirectAttached.equals(vlanRange.getVlanType())) {
+                throw new InvalidParameterValueException("forSystemVms is not available for this IP range with vlan type: " + VlanType.DirectAttached);
+            }
+            // Check if range has already been dedicated
+            final List<AccountVlanMapVO> maps = _accountVlanMapDao.listAccountVlanMapsByVlan(id);
+            if (maps != null && !maps.isEmpty()) {
+                throw new InvalidParameterValueException("Specified Public IP range has already been dedicated to an account");
+            }
+
+            List<DomainVlanMapVO> domainmaps = _domainVlanMapDao.listDomainVlanMapsByVlan(id);
+            if (domainmaps != null && !domainmaps.isEmpty()) {
+                throw new InvalidParameterValueException("Specified Public IP range has already been dedicated to a domain");
+            }
+        }
+        if (ipv4) {
+            if (gateway != null && !gateway.equals(vlanRange.getVlanGateway())) {
+                throw new InvalidParameterValueException("The input gateway " + gateway + " is not same as IP range gateway " + vlanRange.getVlanGateway());
+            }
+            if (netmask != null && !netmask.equals(vlanRange.getVlanNetmask())) {
+                throw new InvalidParameterValueException("The input netmask " + netmask + " is not same as IP range netmask " + vlanRange.getVlanNetmask());
+            }
+
+            if (gateway == null) {
+                gateway = vlanRange.getVlanGateway();
+            }
+
+            if (netmask == null) {
+                netmask = vlanRange.getVlanNetmask();
+            }
+
+            final String[] existingVlanIPRangeArray = vlanRange.getIpRange().split("-");
+            final String currentStartIP = existingVlanIPRangeArray[0];
+            final String currentEndIP = existingVlanIPRangeArray[1];
+
+            if (startIp == null) {
+                startIp = currentStartIP;
+            }
+
+            if (endIp == null) {
+                endIp = currentEndIP;
+            }
+
+            final String cidr = NetUtils.ipAndNetMaskToCidr(gateway, netmask);
+            if (Strings.isNullOrEmpty(cidr)) {
+                throw new InvalidParameterValueException(String.format("Invalid gateway (%s) or netmask (%s)", gateway, netmask));
+            }
+            final String cidrAddress = getCidrAddress(cidr);
+            final long cidrSize = getCidrSize(cidr);
+
+            checkIpRange(currentStartIP, currentEndIP, cidrAddress, cidrSize);
+            if (startIp != currentStartIP || endIp != currentEndIP) {
+                checkIpRange(startIp, endIp, cidrAddress, cidrSize);
+            }
+
+            checkGatewayOverlap(startIp, endIp, gateway);
+
+            final List<IPAddressVO> ips = _publicIpAddressDao.listByVlanId(id);
+            checkAllocatedIpsAreWithinVlanRange(ips, startIp, endIp, forSystemVms);
+
+            try {
+                final String newStartIP = startIp;
+                final String newEndIP = endIp;
+
+                VlanVO range = _vlanDao.acquireInLockTable(id, 30);
+                if (range == null) {
+                    throw new CloudRuntimeException("Unable to acquire vlan configuration: " + id);
+                }
+
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug("lock vlan " + id + " is acquired");
+                }
+
+                commitUpdateVlanAndIpRange(id, newStartIP, newEndIP, currentStartIP, currentEndIP, true, isRangeForSystemVM, forSystemVms);
+
+            } catch (final Exception e) {
+                s_logger.error("Unable to edit VlanRange due to " + e.getMessage(), e);
+                throw new CloudRuntimeException("Failed to edit VlanRange. Please contact Cloud Support.");
+            } finally {
+                _vlanDao.releaseFromLockTable(id);
+            }
+        }
+
+        if (ipv6) {
+            if (ip6Gateway != null && !ip6Gateway.equals(vlanRange.getIp6Gateway())) {
+                throw new InvalidParameterValueException("The input gateway " + ip6Gateway + " is not same as IP range gateway " + vlanRange.getIp6Gateway());
+            }
+            if (ip6Cidr != null && !ip6Cidr.equals(vlanRange.getIp6Cidr())) {
+                throw new InvalidParameterValueException("The input cidr " + ip6Cidr + " is not same as IP range cidr " + vlanRange.getIp6Cidr());
+            }
+            ip6Gateway = MoreObjects.firstNonNull(ip6Gateway, vlanRange.getIp6Gateway());
+            ip6Cidr = MoreObjects.firstNonNull(ip6Cidr, vlanRange.getIp6Cidr());
+
+            final String[] existingVlanIPRangeArray = vlanRange.getIp6Range().split("-");
+            final String currentStartIPv6 = existingVlanIPRangeArray[0];
+            final String currentEndIPv6 = existingVlanIPRangeArray[1];
+
+            if (startIpv6 == null) {
+                startIpv6 = currentStartIPv6;
+            }
+            if (endIpv6 == null) {
+                endIpv6 = currentEndIPv6;
+            }
+            if (startIpv6 != currentStartIPv6 || endIpv6 != currentEndIPv6) {
+                _networkModel.checkIp6Parameters(startIpv6, endIpv6, ip6Gateway, ip6Cidr);
+                final List<UserIpv6AddressVO> ips = _ipv6Dao.listByVlanId(id);
+                checkAllocatedIpv6sAreWithinVlanRange(ips, startIp, endIp);
+
+                try {
+                    VlanVO range = _vlanDao.acquireInLockTable(id, 30);
+                    if (range == null) {
+                        throw new CloudRuntimeException("Unable to acquire vlan configuration: " + id);
+                    }
+
+                    if (s_logger.isDebugEnabled()) {
+                        s_logger.debug("lock vlan " + id + " is acquired");
+                    }
+
+                    commitUpdateVlanAndIpRange(id, startIpv6, endIpv6, currentStartIPv6, currentEndIPv6, false, isRangeForSystemVM,forSystemVms);
+
+                } catch (final Exception e) {
+                    s_logger.error("Unable to edit VlanRange due to " + e.getMessage(), e);
+                    throw new CloudRuntimeException("Failed to edit VlanRange. Please contact Cloud Support.");
+                } finally {
+                    _vlanDao.releaseFromLockTable(id);
+                }
+            }
+        }
+
+        return _vlanDao.findById(id);
+    }
+
+    private VlanVO commitUpdateVlanAndIpRange(final Long id, final String newStartIP, final String newEndIP, final String currentStartIP, final String currentEndIP,
+                                              final boolean ipv4, final Boolean isRangeForSystemVM, final Boolean forSystemvms) {
+
+        return Transaction.execute(new TransactionCallback<VlanVO>() {
+            @Override
+            public VlanVO doInTransaction(final TransactionStatus status) {
+                VlanVO vlanRange = _vlanDao.findById(id);
+                s_logger.debug("Updating vlan range " + vlanRange.getId());
+                if (ipv4) {
+                    vlanRange.setIpRange(newStartIP + "-" + newEndIP);
+                    _vlanDao.update(vlanRange.getId(), vlanRange);
+                    if (!updatePublicIPRange(newStartIP, currentStartIP, newEndIP, currentEndIP, vlanRange.getDataCenterId(), vlanRange.getId(), vlanRange.getNetworkId(), vlanRange.getPhysicalNetworkId(), isRangeForSystemVM, forSystemvms)) {
+                        throw new CloudRuntimeException("Failed to update IPv4 range. Please contact Cloud Support.");
+                    }
+                } else {
+                    vlanRange.setIp6Range(newStartIP + "-" + newEndIP);
+                    _vlanDao.update(vlanRange.getId(), vlanRange);
+                }
+                return vlanRange;
+            }
+        });
+    }
+
+    private boolean checkIfVlanRangeIsForSystemVM(final long vlanId) {
+        List<IPAddressVO> existingPublicIPs = _publicIpAddressDao.listByVlanId(vlanId);
+        boolean initialIsSystemVmValue = existingPublicIPs.get(0).isForSystemVms();
+        for (IPAddressVO existingIPs : existingPublicIPs) {
+            if (initialIsSystemVmValue != existingIPs.isForSystemVms()) {
+                throw new CloudRuntimeException("Your \"For System VM\" value seems to be inconsistent with the rest of the records. Please contact Cloud Support");
+            }
+        }
+        return initialIsSystemVmValue;
+    }
+
+    private void checkAllocatedIpsAreWithinVlanRange(List<IPAddressVO> ips, String startIp, String endIp, Boolean forSystemVms) {
+
+        List<IPAddressVO> listAllocatedIPs = new ArrayList<>();
+        for (final IPAddressVO ip : ips) {
+            if (ip.getState() == IpAddress.State.Allocated) {
+                listAllocatedIPs.add(ip);
+            }
+        }
+        Collections.sort(listAllocatedIPs, Comparator.comparing(IPAddressVO::getAddress));
+        for (IPAddressVO allocatedIP : listAllocatedIPs) {
+            if (!Strings.isNullOrEmpty(startIp) && NetUtils.ip2Long(startIp) > NetUtils.ip2Long(allocatedIP.getAddress().addr())) {
+                throw new InvalidParameterValueException("The start IP address must have a lower IP address value "
+                        + "than " + allocatedIP.getAddress() + " which is already in use. The end IP must have a "
+                        + "higher IP address than " + listAllocatedIPs.get(listAllocatedIPs.size() - 1).getAddress() + " .IPs "
+                        + "already allocated in this range: " + listAllocatedIPs.size());
+            }
+            if (!Strings.isNullOrEmpty(endIp) && NetUtils.ip2Long(endIp) < NetUtils.ip2Long(allocatedIP.getAddress().addr())) {
+                throw new InvalidParameterValueException("The start IP address must have a lower IP address value "
+                        + "than " + listAllocatedIPs.get(0).getAddress() + " which is already in use. The end IP must have a "
+                        + "higher IP address than " +  allocatedIP.getAddress() + " .IPs "
+                        + "already allocated in this range: " + listAllocatedIPs.size());

Review comment:
       here to, can you use `String.format()`?

##########
File path: server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
##########
@@ -4237,6 +4246,274 @@ public VlanVO doInTransaction(final TransactionStatus status) {
 
     }
 
+    @Override
+    public Vlan updateVlanAndPublicIpRange(UpdateVlanIpRangeCmd cmd) throws ConcurrentOperationException,
+            ResourceUnavailableException,ResourceAllocationException {
+
+        return  updateVlanAndPublicIpRange(cmd.getId(), cmd.getStartIp(),cmd.getEndIp(), cmd.getGateway(),cmd.getNetmask(),
+                cmd.getStartIpv6(), cmd.getEndIpv6(), cmd.getIp6Gateway(), cmd.getIp6Cidr(), cmd.isForSystemVms());
+    }
+
+    @DB
+    @ActionEvent(eventType = EventTypes.EVENT_VLAN_IP_RANGE_UPDATE, eventDescription = "update vlan ip Range", async
+            = false)
+    public Vlan updateVlanAndPublicIpRange(final long id, String startIp,
+                                           String endIp,
+                                           String gateway,
+                                           String netmask,
+                                           String startIpv6,
+                                           String endIpv6,
+                                           String ip6Gateway,
+                                           String ip6Cidr,
+                                           Boolean forSystemVms) throws ConcurrentOperationException {
+
+        VlanVO vlanRange = _vlanDao.findById(id);
+        if (vlanRange == null) {
+            throw new InvalidParameterValueException("Please specify a valid IP range id.");
+        }
+
+        final boolean ipv4 = vlanRange.getVlanGateway() != null;
+        final boolean ipv6 = vlanRange.getIp6Gateway() != null;
+        if (!ipv4) {
+            if (startIp != null || endIp != null || gateway != null || netmask != null) {
+                throw new InvalidParameterValueException("IPv4 is not support in this IP range.");
+            }
+        }
+        if (!ipv6) {
+            if (startIpv6 != null || endIpv6 != null || ip6Gateway != null || ip6Cidr != null) {
+                throw new InvalidParameterValueException("IPv6 is not support in this IP range.");
+            }
+        }
+
+        final Boolean isRangeForSystemVM = checkIfVlanRangeIsForSystemVM(id);
+        if (forSystemVms != null && isRangeForSystemVM != forSystemVms) {
+            if (VlanType.DirectAttached.equals(vlanRange.getVlanType())) {
+                throw new InvalidParameterValueException("forSystemVms is not available for this IP range with vlan type: " + VlanType.DirectAttached);
+            }
+            // Check if range has already been dedicated
+            final List<AccountVlanMapVO> maps = _accountVlanMapDao.listAccountVlanMapsByVlan(id);
+            if (maps != null && !maps.isEmpty()) {
+                throw new InvalidParameterValueException("Specified Public IP range has already been dedicated to an account");
+            }
+
+            List<DomainVlanMapVO> domainmaps = _domainVlanMapDao.listDomainVlanMapsByVlan(id);
+            if (domainmaps != null && !domainmaps.isEmpty()) {
+                throw new InvalidParameterValueException("Specified Public IP range has already been dedicated to a domain");
+            }
+        }
+        if (ipv4) {
+            if (gateway != null && !gateway.equals(vlanRange.getVlanGateway())) {
+                throw new InvalidParameterValueException("The input gateway " + gateway + " is not same as IP range gateway " + vlanRange.getVlanGateway());
+            }
+            if (netmask != null && !netmask.equals(vlanRange.getVlanNetmask())) {
+                throw new InvalidParameterValueException("The input netmask " + netmask + " is not same as IP range netmask " + vlanRange.getVlanNetmask());
+            }
+
+            if (gateway == null) {
+                gateway = vlanRange.getVlanGateway();
+            }
+
+            if (netmask == null) {
+                netmask = vlanRange.getVlanNetmask();
+            }
+
+            final String[] existingVlanIPRangeArray = vlanRange.getIpRange().split("-");
+            final String currentStartIP = existingVlanIPRangeArray[0];
+            final String currentEndIP = existingVlanIPRangeArray[1];
+
+            if (startIp == null) {
+                startIp = currentStartIP;
+            }
+
+            if (endIp == null) {
+                endIp = currentEndIP;
+            }
+
+            final String cidr = NetUtils.ipAndNetMaskToCidr(gateway, netmask);
+            if (Strings.isNullOrEmpty(cidr)) {
+                throw new InvalidParameterValueException(String.format("Invalid gateway (%s) or netmask (%s)", gateway, netmask));
+            }
+            final String cidrAddress = getCidrAddress(cidr);
+            final long cidrSize = getCidrSize(cidr);
+
+            checkIpRange(currentStartIP, currentEndIP, cidrAddress, cidrSize);
+            if (startIp != currentStartIP || endIp != currentEndIP) {
+                checkIpRange(startIp, endIp, cidrAddress, cidrSize);
+            }
+
+            checkGatewayOverlap(startIp, endIp, gateway);
+
+            final List<IPAddressVO> ips = _publicIpAddressDao.listByVlanId(id);
+            checkAllocatedIpsAreWithinVlanRange(ips, startIp, endIp, forSystemVms);
+
+            try {
+                final String newStartIP = startIp;
+                final String newEndIP = endIp;
+
+                VlanVO range = _vlanDao.acquireInLockTable(id, 30);
+                if (range == null) {
+                    throw new CloudRuntimeException("Unable to acquire vlan configuration: " + id);
+                }
+
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug("lock vlan " + id + " is acquired");
+                }
+
+                commitUpdateVlanAndIpRange(id, newStartIP, newEndIP, currentStartIP, currentEndIP, true, isRangeForSystemVM, forSystemVms);
+
+            } catch (final Exception e) {
+                s_logger.error("Unable to edit VlanRange due to " + e.getMessage(), e);
+                throw new CloudRuntimeException("Failed to edit VlanRange. Please contact Cloud Support.");
+            } finally {
+                _vlanDao.releaseFromLockTable(id);
+            }
+        }
+
+        if (ipv6) {
+            if (ip6Gateway != null && !ip6Gateway.equals(vlanRange.getIp6Gateway())) {
+                throw new InvalidParameterValueException("The input gateway " + ip6Gateway + " is not same as IP range gateway " + vlanRange.getIp6Gateway());
+            }
+            if (ip6Cidr != null && !ip6Cidr.equals(vlanRange.getIp6Cidr())) {
+                throw new InvalidParameterValueException("The input cidr " + ip6Cidr + " is not same as IP range cidr " + vlanRange.getIp6Cidr());
+            }
+            ip6Gateway = MoreObjects.firstNonNull(ip6Gateway, vlanRange.getIp6Gateway());
+            ip6Cidr = MoreObjects.firstNonNull(ip6Cidr, vlanRange.getIp6Cidr());
+
+            final String[] existingVlanIPRangeArray = vlanRange.getIp6Range().split("-");
+            final String currentStartIPv6 = existingVlanIPRangeArray[0];
+            final String currentEndIPv6 = existingVlanIPRangeArray[1];
+
+            if (startIpv6 == null) {
+                startIpv6 = currentStartIPv6;
+            }
+            if (endIpv6 == null) {
+                endIpv6 = currentEndIPv6;
+            }
+            if (startIpv6 != currentStartIPv6 || endIpv6 != currentEndIPv6) {
+                _networkModel.checkIp6Parameters(startIpv6, endIpv6, ip6Gateway, ip6Cidr);
+                final List<UserIpv6AddressVO> ips = _ipv6Dao.listByVlanId(id);
+                checkAllocatedIpv6sAreWithinVlanRange(ips, startIp, endIp);
+
+                try {
+                    VlanVO range = _vlanDao.acquireInLockTable(id, 30);
+                    if (range == null) {
+                        throw new CloudRuntimeException("Unable to acquire vlan configuration: " + id);
+                    }
+
+                    if (s_logger.isDebugEnabled()) {
+                        s_logger.debug("lock vlan " + id + " is acquired");
+                    }
+
+                    commitUpdateVlanAndIpRange(id, startIpv6, endIpv6, currentStartIPv6, currentEndIPv6, false, isRangeForSystemVM,forSystemVms);
+
+                } catch (final Exception e) {
+                    s_logger.error("Unable to edit VlanRange due to " + e.getMessage(), e);
+                    throw new CloudRuntimeException("Failed to edit VlanRange. Please contact Cloud Support.");
+                } finally {
+                    _vlanDao.releaseFromLockTable(id);
+                }
+            }
+        }
+
+        return _vlanDao.findById(id);
+    }
+
+    private VlanVO commitUpdateVlanAndIpRange(final Long id, final String newStartIP, final String newEndIP, final String currentStartIP, final String currentEndIP,
+                                              final boolean ipv4, final Boolean isRangeForSystemVM, final Boolean forSystemvms) {
+
+        return Transaction.execute(new TransactionCallback<VlanVO>() {
+            @Override
+            public VlanVO doInTransaction(final TransactionStatus status) {
+                VlanVO vlanRange = _vlanDao.findById(id);
+                s_logger.debug("Updating vlan range " + vlanRange.getId());
+                if (ipv4) {
+                    vlanRange.setIpRange(newStartIP + "-" + newEndIP);
+                    _vlanDao.update(vlanRange.getId(), vlanRange);
+                    if (!updatePublicIPRange(newStartIP, currentStartIP, newEndIP, currentEndIP, vlanRange.getDataCenterId(), vlanRange.getId(), vlanRange.getNetworkId(), vlanRange.getPhysicalNetworkId(), isRangeForSystemVM, forSystemvms)) {
+                        throw new CloudRuntimeException("Failed to update IPv4 range. Please contact Cloud Support.");
+                    }
+                } else {
+                    vlanRange.setIp6Range(newStartIP + "-" + newEndIP);
+                    _vlanDao.update(vlanRange.getId(), vlanRange);
+                }
+                return vlanRange;
+            }
+        });
+    }
+
+    private boolean checkIfVlanRangeIsForSystemVM(final long vlanId) {
+        List<IPAddressVO> existingPublicIPs = _publicIpAddressDao.listByVlanId(vlanId);
+        boolean initialIsSystemVmValue = existingPublicIPs.get(0).isForSystemVms();
+        for (IPAddressVO existingIPs : existingPublicIPs) {
+            if (initialIsSystemVmValue != existingIPs.isForSystemVms()) {
+                throw new CloudRuntimeException("Your \"For System VM\" value seems to be inconsistent with the rest of the records. Please contact Cloud Support");
+            }
+        }
+        return initialIsSystemVmValue;
+    }
+
+    private void checkAllocatedIpsAreWithinVlanRange(List<IPAddressVO> ips, String startIp, String endIp, Boolean forSystemVms) {
+
+        List<IPAddressVO> listAllocatedIPs = new ArrayList<>();
+        for (final IPAddressVO ip : ips) {
+            if (ip.getState() == IpAddress.State.Allocated) {
+                listAllocatedIPs.add(ip);
+            }
+        }
+        Collections.sort(listAllocatedIPs, Comparator.comparing(IPAddressVO::getAddress));
+        for (IPAddressVO allocatedIP : listAllocatedIPs) {
+            if (!Strings.isNullOrEmpty(startIp) && NetUtils.ip2Long(startIp) > NetUtils.ip2Long(allocatedIP.getAddress().addr())) {
+                throw new InvalidParameterValueException("The start IP address must have a lower IP address value "
+                        + "than " + allocatedIP.getAddress() + " which is already in use. The end IP must have a "
+                        + "higher IP address than " + listAllocatedIPs.get(listAllocatedIPs.size() - 1).getAddress() + " .IPs "
+                        + "already allocated in this range: " + listAllocatedIPs.size());

Review comment:
       `String.format(..)` ?

##########
File path: server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
##########
@@ -4237,6 +4246,274 @@ public VlanVO doInTransaction(final TransactionStatus status) {
 
     }
 
+    @Override
+    public Vlan updateVlanAndPublicIpRange(UpdateVlanIpRangeCmd cmd) throws ConcurrentOperationException,
+            ResourceUnavailableException,ResourceAllocationException {
+
+        return  updateVlanAndPublicIpRange(cmd.getId(), cmd.getStartIp(),cmd.getEndIp(), cmd.getGateway(),cmd.getNetmask(),
+                cmd.getStartIpv6(), cmd.getEndIpv6(), cmd.getIp6Gateway(), cmd.getIp6Cidr(), cmd.isForSystemVms());
+    }
+
+    @DB
+    @ActionEvent(eventType = EventTypes.EVENT_VLAN_IP_RANGE_UPDATE, eventDescription = "update vlan ip Range", async
+            = false)
+    public Vlan updateVlanAndPublicIpRange(final long id, String startIp,
+                                           String endIp,
+                                           String gateway,
+                                           String netmask,
+                                           String startIpv6,
+                                           String endIpv6,
+                                           String ip6Gateway,
+                                           String ip6Cidr,
+                                           Boolean forSystemVms) throws ConcurrentOperationException {
+
+        VlanVO vlanRange = _vlanDao.findById(id);
+        if (vlanRange == null) {
+            throw new InvalidParameterValueException("Please specify a valid IP range id.");
+        }
+
+        final boolean ipv4 = vlanRange.getVlanGateway() != null;
+        final boolean ipv6 = vlanRange.getIp6Gateway() != null;
+        if (!ipv4) {
+            if (startIp != null || endIp != null || gateway != null || netmask != null) {
+                throw new InvalidParameterValueException("IPv4 is not support in this IP range.");
+            }
+        }
+        if (!ipv6) {
+            if (startIpv6 != null || endIpv6 != null || ip6Gateway != null || ip6Cidr != null) {
+                throw new InvalidParameterValueException("IPv6 is not support in this IP range.");
+            }
+        }
+
+        final Boolean isRangeForSystemVM = checkIfVlanRangeIsForSystemVM(id);
+        if (forSystemVms != null && isRangeForSystemVM != forSystemVms) {
+            if (VlanType.DirectAttached.equals(vlanRange.getVlanType())) {
+                throw new InvalidParameterValueException("forSystemVms is not available for this IP range with vlan type: " + VlanType.DirectAttached);
+            }
+            // Check if range has already been dedicated
+            final List<AccountVlanMapVO> maps = _accountVlanMapDao.listAccountVlanMapsByVlan(id);
+            if (maps != null && !maps.isEmpty()) {
+                throw new InvalidParameterValueException("Specified Public IP range has already been dedicated to an account");
+            }
+
+            List<DomainVlanMapVO> domainmaps = _domainVlanMapDao.listDomainVlanMapsByVlan(id);
+            if (domainmaps != null && !domainmaps.isEmpty()) {
+                throw new InvalidParameterValueException("Specified Public IP range has already been dedicated to a domain");
+            }
+        }
+        if (ipv4) {
+            if (gateway != null && !gateway.equals(vlanRange.getVlanGateway())) {
+                throw new InvalidParameterValueException("The input gateway " + gateway + " is not same as IP range gateway " + vlanRange.getVlanGateway());
+            }
+            if (netmask != null && !netmask.equals(vlanRange.getVlanNetmask())) {
+                throw new InvalidParameterValueException("The input netmask " + netmask + " is not same as IP range netmask " + vlanRange.getVlanNetmask());
+            }
+
+            if (gateway == null) {
+                gateway = vlanRange.getVlanGateway();
+            }
+
+            if (netmask == null) {
+                netmask = vlanRange.getVlanNetmask();
+            }
+
+            final String[] existingVlanIPRangeArray = vlanRange.getIpRange().split("-");
+            final String currentStartIP = existingVlanIPRangeArray[0];
+            final String currentEndIP = existingVlanIPRangeArray[1];
+
+            if (startIp == null) {
+                startIp = currentStartIP;
+            }
+
+            if (endIp == null) {
+                endIp = currentEndIP;
+            }
+
+            final String cidr = NetUtils.ipAndNetMaskToCidr(gateway, netmask);
+            if (Strings.isNullOrEmpty(cidr)) {
+                throw new InvalidParameterValueException(String.format("Invalid gateway (%s) or netmask (%s)", gateway, netmask));
+            }
+            final String cidrAddress = getCidrAddress(cidr);
+            final long cidrSize = getCidrSize(cidr);
+
+            checkIpRange(currentStartIP, currentEndIP, cidrAddress, cidrSize);
+            if (startIp != currentStartIP || endIp != currentEndIP) {
+                checkIpRange(startIp, endIp, cidrAddress, cidrSize);
+            }
+
+            checkGatewayOverlap(startIp, endIp, gateway);
+
+            final List<IPAddressVO> ips = _publicIpAddressDao.listByVlanId(id);
+            checkAllocatedIpsAreWithinVlanRange(ips, startIp, endIp, forSystemVms);
+
+            try {
+                final String newStartIP = startIp;
+                final String newEndIP = endIp;
+
+                VlanVO range = _vlanDao.acquireInLockTable(id, 30);
+                if (range == null) {
+                    throw new CloudRuntimeException("Unable to acquire vlan configuration: " + id);
+                }
+
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug("lock vlan " + id + " is acquired");
+                }
+
+                commitUpdateVlanAndIpRange(id, newStartIP, newEndIP, currentStartIP, currentEndIP, true, isRangeForSystemVM, forSystemVms);
+
+            } catch (final Exception e) {
+                s_logger.error("Unable to edit VlanRange due to " + e.getMessage(), e);
+                throw new CloudRuntimeException("Failed to edit VlanRange. Please contact Cloud Support.");
+            } finally {
+                _vlanDao.releaseFromLockTable(id);
+            }
+        }
+
+        if (ipv6) {
+            if (ip6Gateway != null && !ip6Gateway.equals(vlanRange.getIp6Gateway())) {
+                throw new InvalidParameterValueException("The input gateway " + ip6Gateway + " is not same as IP range gateway " + vlanRange.getIp6Gateway());
+            }
+            if (ip6Cidr != null && !ip6Cidr.equals(vlanRange.getIp6Cidr())) {
+                throw new InvalidParameterValueException("The input cidr " + ip6Cidr + " is not same as IP range cidr " + vlanRange.getIp6Cidr());
+            }
+            ip6Gateway = MoreObjects.firstNonNull(ip6Gateway, vlanRange.getIp6Gateway());
+            ip6Cidr = MoreObjects.firstNonNull(ip6Cidr, vlanRange.getIp6Cidr());
+
+            final String[] existingVlanIPRangeArray = vlanRange.getIp6Range().split("-");
+            final String currentStartIPv6 = existingVlanIPRangeArray[0];
+            final String currentEndIPv6 = existingVlanIPRangeArray[1];
+
+            if (startIpv6 == null) {
+                startIpv6 = currentStartIPv6;
+            }
+            if (endIpv6 == null) {
+                endIpv6 = currentEndIPv6;
+            }
+            if (startIpv6 != currentStartIPv6 || endIpv6 != currentEndIPv6) {
+                _networkModel.checkIp6Parameters(startIpv6, endIpv6, ip6Gateway, ip6Cidr);
+                final List<UserIpv6AddressVO> ips = _ipv6Dao.listByVlanId(id);
+                checkAllocatedIpv6sAreWithinVlanRange(ips, startIp, endIp);
+
+                try {
+                    VlanVO range = _vlanDao.acquireInLockTable(id, 30);
+                    if (range == null) {
+                        throw new CloudRuntimeException("Unable to acquire vlan configuration: " + id);
+                    }
+
+                    if (s_logger.isDebugEnabled()) {
+                        s_logger.debug("lock vlan " + id + " is acquired");
+                    }
+
+                    commitUpdateVlanAndIpRange(id, startIpv6, endIpv6, currentStartIPv6, currentEndIPv6, false, isRangeForSystemVM,forSystemVms);
+
+                } catch (final Exception e) {
+                    s_logger.error("Unable to edit VlanRange due to " + e.getMessage(), e);
+                    throw new CloudRuntimeException("Failed to edit VlanRange. Please contact Cloud Support.");
+                } finally {
+                    _vlanDao.releaseFromLockTable(id);
+                }
+            }
+        }
+
+        return _vlanDao.findById(id);
+    }
+
+    private VlanVO commitUpdateVlanAndIpRange(final Long id, final String newStartIP, final String newEndIP, final String currentStartIP, final String currentEndIP,
+                                              final boolean ipv4, final Boolean isRangeForSystemVM, final Boolean forSystemvms) {
+
+        return Transaction.execute(new TransactionCallback<VlanVO>() {
+            @Override
+            public VlanVO doInTransaction(final TransactionStatus status) {
+                VlanVO vlanRange = _vlanDao.findById(id);
+                s_logger.debug("Updating vlan range " + vlanRange.getId());
+                if (ipv4) {
+                    vlanRange.setIpRange(newStartIP + "-" + newEndIP);
+                    _vlanDao.update(vlanRange.getId(), vlanRange);
+                    if (!updatePublicIPRange(newStartIP, currentStartIP, newEndIP, currentEndIP, vlanRange.getDataCenterId(), vlanRange.getId(), vlanRange.getNetworkId(), vlanRange.getPhysicalNetworkId(), isRangeForSystemVM, forSystemvms)) {
+                        throw new CloudRuntimeException("Failed to update IPv4 range. Please contact Cloud Support.");
+                    }
+                } else {
+                    vlanRange.setIp6Range(newStartIP + "-" + newEndIP);
+                    _vlanDao.update(vlanRange.getId(), vlanRange);
+                }
+                return vlanRange;
+            }
+        });
+    }
+
+    private boolean checkIfVlanRangeIsForSystemVM(final long vlanId) {
+        List<IPAddressVO> existingPublicIPs = _publicIpAddressDao.listByVlanId(vlanId);
+        boolean initialIsSystemVmValue = existingPublicIPs.get(0).isForSystemVms();
+        for (IPAddressVO existingIPs : existingPublicIPs) {
+            if (initialIsSystemVmValue != existingIPs.isForSystemVms()) {
+                throw new CloudRuntimeException("Your \"For System VM\" value seems to be inconsistent with the rest of the records. Please contact Cloud Support");
+            }
+        }
+        return initialIsSystemVmValue;
+    }
+
+    private void checkAllocatedIpsAreWithinVlanRange(List<IPAddressVO> ips, String startIp, String endIp, Boolean forSystemVms) {
+
+        List<IPAddressVO> listAllocatedIPs = new ArrayList<>();
+        for (final IPAddressVO ip : ips) {
+            if (ip.getState() == IpAddress.State.Allocated) {
+                listAllocatedIPs.add(ip);
+            }
+        }
+        Collections.sort(listAllocatedIPs, Comparator.comparing(IPAddressVO::getAddress));
+        for (IPAddressVO allocatedIP : listAllocatedIPs) {
+            if (!Strings.isNullOrEmpty(startIp) && NetUtils.ip2Long(startIp) > NetUtils.ip2Long(allocatedIP.getAddress().addr())) {
+                throw new InvalidParameterValueException("The start IP address must have a lower IP address value "
+                        + "than " + allocatedIP.getAddress() + " which is already in use. The end IP must have a "
+                        + "higher IP address than " + listAllocatedIPs.get(listAllocatedIPs.size() - 1).getAddress() + " .IPs "
+                        + "already allocated in this range: " + listAllocatedIPs.size());
+            }
+            if (!Strings.isNullOrEmpty(endIp) && NetUtils.ip2Long(endIp) < NetUtils.ip2Long(allocatedIP.getAddress().addr())) {
+                throw new InvalidParameterValueException("The start IP address must have a lower IP address value "
+                        + "than " + listAllocatedIPs.get(0).getAddress() + " which is already in use. The end IP must have a "
+                        + "higher IP address than " +  allocatedIP.getAddress() + " .IPs "
+                        + "already allocated in this range: " + listAllocatedIPs.size());
+            }
+            if (forSystemVms != null && allocatedIP.isForSystemVms() != forSystemVms) {
+                throw new InvalidParameterValueException(String.format("IP %s is in use, cannot change forSystemVms of the IP range", allocatedIP.getAddress().addr()));
+            }
+        }
+    }
+
+    private void checkAllocatedIpv6sAreWithinVlanRange(List<UserIpv6AddressVO> ips, String startIpv6, String endIpv6) {
+
+        List<UserIpv6AddressVO> listAllocatedIPs = new ArrayList<>();
+        for (final UserIpv6AddressVO ip : ips) {
+            if (ip.getState() == UserIpv6Address.State.Allocated) {
+                listAllocatedIPs.add(ip);
+            }
+        }
+        Collections.sort(listAllocatedIPs, Comparator.comparing(UserIpv6AddressVO::getAddress));
+        for (UserIpv6AddressVO allocatedIP : listAllocatedIPs) {
+            if (!Strings.isNullOrEmpty(startIpv6)
+                    && IPv6Address.fromString(startIpv6).toBigInteger().compareTo(IPv6Address.fromString(allocatedIP.getAddress()).toBigInteger()) > 0) {
+                throw new InvalidParameterValueException("The start IP address must have a lower IP address value "
+                        + "than " + allocatedIP.getAddress() + " which is already in use. The end IP must have a "
+                        + "higher IP address than " + listAllocatedIPs.get(listAllocatedIPs.size() - 1).getAddress() + " .IPs "
+                        + "already allocated in this range: " + listAllocatedIPs.size());
+            }

Review comment:
       and this




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@cloudstack.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org