From b29e3c5a2452fff583d22482673cd954f058b0a3 Mon Sep 17 00:00:00 2001 From: kioie Date: Sun, 29 Mar 2020 09:11:29 +0300 Subject: [PATCH 01/14] Added Logic to update the user_ip_address table --- .../configuration/ConfigurationService.java | 17 ++ .../main/java/com/cloud/event/EventTypes.java | 1 + .../admin/vlan/UpdateVlanIpRangeCmd.java | 158 ++++++++++++++ .../configuration/ConfigurationManager.java | 5 + .../src/main/java/com/cloud/dc/VlanVO.java | 2 +- .../ConfigurationManagerImpl.java | 201 ++++++++++++++++++ .../cloud/server/ManagementServerImpl.java | 2 + .../java/com/cloud/test/IPRangeConfig.java | 44 ++-- .../vpc/MockConfigurationManagerImpl.java | 12 ++ 9 files changed, 421 insertions(+), 21 deletions(-) create mode 100644 api/src/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmd.java diff --git a/api/src/main/java/com/cloud/configuration/ConfigurationService.java b/api/src/main/java/com/cloud/configuration/ConfigurationService.java index 8b419027f702..98fea0ecab77 100644 --- a/api/src/main/java/com/cloud/configuration/ConfigurationService.java +++ b/api/src/main/java/com/cloud/configuration/ConfigurationService.java @@ -39,6 +39,7 @@ 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.vlan.UpdateVlanIpRangeCmd; 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; @@ -272,6 +273,22 @@ public interface ConfigurationService { Vlan createVlanAndPublicIpRange(CreateVlanIpRangeCmd cmd) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, ResourceAllocationException; + /** + * Updates the IP address Range for the VLAN on the database, a + * + * @param cmd + * @param vlanId + * @param gateway + * @param startIP + * @param endIP + * @param netmask + * @throws com.cloud.exception.ConcurrentOperationException + * @throws com.cloud.exception.ResourceUnavailableException + * @throws com.cloud.exception.ResourceAllocationException + * @return The updated Vlan object + */ + Vlan updateVlanAndPublicIpRange(UpdateVlanIpRangeCmd cmd) throws ConcurrentOperationException, + ResourceUnavailableException, ResourceAllocationException; /** * Marks the the account with the default zone-id. * diff --git a/api/src/main/java/com/cloud/event/EventTypes.java b/api/src/main/java/com/cloud/event/EventTypes.java index 30b6ac0b0a17..ed60d040645f 100644 --- a/api/src/main/java/com/cloud/event/EventTypes.java +++ b/api/src/main/java/com/cloud/event/EventTypes.java @@ -311,6 +311,7 @@ public class EventTypes { 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_VLAN_IP_RANGE_UPDATE = "VLAN.IP.RANGE.UPDATE"; 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"; diff --git a/api/src/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmd.java b/api/src/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmd.java new file mode 100644 index 000000000000..b5e6aff42cd4 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmd.java @@ -0,0 +1,158 @@ +// 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.BaseAsyncCmd; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.VlanIpRangeResponse; +import org.apache.log4j.Logger; + +import com.cloud.dc.Vlan; +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; +import com.cloud.utils.net.NetUtils; + +@APICommand(name = UpdateVlanIpRangeCmd.APINAME, description = "Updates a VLAN IP range.", responseObject = + VlanIpRangeResponse.class, since = "4.13.0", + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) +public class UpdateVlanIpRangeCmd extends BaseAsyncCmd { + + public static final String APINAME = "updateVlanIpRange"; + public static final Logger s_logger = Logger.getLogger(UpdateVlanIpRangeCmd.class.getName()); + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + + @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = VlanIpRangeResponse.class, required = true, + description = "the UUID of the VLAN IP range") + private Long id; + + @Parameter(name = ApiConstants.END_IP, type = CommandType.STRING, + description = "the ending IP address in the VLAN IP range") + private String endIp; + + @Parameter(name = ApiConstants.GATEWAY, type = CommandType.STRING, description = "the gateway of the VLAN IP range") + private String gateway; + + @Parameter(name = ApiConstants.NETMASK, type = CommandType.STRING, description = "the netmask of the VLAN IP range") + private String netmask; + + @Parameter(name = ApiConstants.START_IP, type = CommandType.STRING, description = "the beginning IP address in the VLAN IP range") + private String startIp; + + @Parameter(name = ApiConstants.START_IPV6, type = CommandType.STRING, description = "the beginning IPv6 address in the IPv6 network range") + private String startIpv6; + + @Parameter(name = ApiConstants.END_IPV6, type = CommandType.STRING, description = "the ending IPv6 address in the IPv6 network range") + private String endIpv6; + + @Parameter(name = ApiConstants.VLAN, type = CommandType.INTEGER, description = "Optional. the vlan the ip range sits on") + private Integer vlan; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + public Long getId() { + return id; + } + + public String getGateway() { + return gateway; + } + + public String getEndIp() { + return endIp; + } + + public String getNetmask() { + return netmask; + } + + public String getStartIp() { + return startIp; + } + + public String getStartIpv6() { + if (startIpv6 == null) { + return null; + } + return NetUtils.standardizeIp6Address(startIpv6); + } + + public String getEndIpv6() { + if (endIpv6 == null) { + return null; + } + return NetUtils.standardizeIp6Address(endIpv6); + } + + public Integer getVlan() { + return vlan; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getEventType() { + return EventTypes.EVENT_VLAN_IP_RANGE_UPDATE; + } + + @Override + public String getEventDescription() { + return "Update vlan ip range " + getId() + " [StartIp=" + getStartIp() + ", EndIp=" + getEndIp() + ", vlan=" + getVlan() + ", netmask=" + getNetmask() + ']'; + } + + + @Override + public void execute() throws ResourceUnavailableException, ResourceAllocationException { + try { + Vlan result = _configService.updateVlanAndPublicIpRange(this); + if (result != null) { + VlanIpRangeResponse response = _responseGenerator.createVlanIpRangeResponse(result); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to Update vlan ip range"); + } + } catch (ConcurrentOperationException ex) { + s_logger.warn("Exception: ", ex); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage()); + } + } + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } +} \ No newline at end of file diff --git a/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java b/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java index 162a61e47373..3fc5ab42c122 100644 --- a/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java +++ b/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java @@ -220,6 +220,11 @@ Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetwor String vlanGateway, String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, Account vlanOwner, String startIPv6, String endIPv6, String vlanIp6Gateway, String vlanIp6Cidr) throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException; + /* (non-Javadoc) + * @see com.cloud.configuration.ConfigurationManager#updateVlanAndPublicIpRange(long,String,String,String,String) + */ + Vlan updateVlanAndPublicIpRange(long id, String startIp, String endIp, String gateway, String netmask) throws ConcurrentOperationException; + void createDefaultSystemNetworks(long zoneId) throws ConcurrentOperationException; /** diff --git a/engine/schema/src/main/java/com/cloud/dc/VlanVO.java b/engine/schema/src/main/java/com/cloud/dc/VlanVO.java index ebbd4bde08b2..91d2bdb6129e 100644 --- a/engine/schema/src/main/java/com/cloud/dc/VlanVO.java +++ b/engine/schema/src/main/java/com/cloud/dc/VlanVO.java @@ -234,6 +234,6 @@ public void setIp6Range(String ip6Range) { } public void setIpRange(String ipRange) { - this.ip6Range = ipRange; + this.ipRange = ipRange; } } diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index 7e9c9d39c2b1..a2c9c8e79ab3 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -26,6 +26,10 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +<<<<<<< HEAD:server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +======= +import java.util.Comparator; +>>>>>>> Added Logic to update the user_ip_address table:server/src/com/cloud/configuration/ConfigurationManagerImpl.java import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -35,10 +39,17 @@ import java.util.Map.Entry; import java.util.Set; import java.util.UUID; +import java.util.Vector; import javax.inject.Inject; import javax.naming.ConfigurationException; +<<<<<<< HEAD:server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +======= +import com.cloud.network.IpAddress; +import com.google.common.collect.Sets; + +>>>>>>> Added Logic to update the user_ip_address table:server/src/com/cloud/configuration/ConfigurationManagerImpl.java import org.apache.cloudstack.acl.SecurityChecker; import org.apache.cloudstack.affinity.AffinityGroup; import org.apache.cloudstack.affinity.AffinityGroupService; @@ -67,6 +78,7 @@ 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.vlan.UpdateVlanIpRangeCmd; 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; @@ -1771,6 +1783,7 @@ private void checkZoneParameters(final String zoneName, final String dns1, final } } + private void checkIpRange(final String startIp, final String endIp, final String cidrAddress, final long cidrSize) { //Checking not null for start IP as well. Previously we assumed to be not null always. //But the check is required for the change in updatePod API. @@ -4075,6 +4088,149 @@ 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()); + } + + @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) throws ConcurrentOperationException{ + + VlanVO vlanRange = _vlanDao.findById(id); + if (vlanRange == null) { + throw new InvalidParameterValueException("Please specify a valid IP range id."); + } + + 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 List ips = _publicIpAddressDao.listByVlanId(id); + checkAllocatedIpsAreWithinVlanRange(ips,startIp,endIp); + + final String cidr = NetUtils.ipAndNetMaskToCidr(gateway, netmask); + final String cidrAddress = getCidrAddress(cidr); + final long cidrSize = getCidrSize(cidr); + + checkIpRange(currentStartIP,currentEndIP,cidrAddress,cidrSize); + + checkIpRange(startIp, endIp, cidrAddress, cidrSize); + + checkGatewayOverlap(startIp,endIp,gateway); + + VlanVO range; + try { + final String newStartIP= startIp; + final String newEndIP= endIp; + + 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); + + } 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 vlanRange; + } + private VlanVO commitUpdateVlanAndIpRange(final Long id, final String newStartIP, final String newEndIP,final String currentStartIP, final String currentEndIP, final boolean ipv4) { + return Transaction.execute(new TransactionCallback() { + @Override + public VlanVO doInTransaction(final TransactionStatus status) { + VlanVO vlanRange = _vlanDao.findById(id); + s_logger.debug("Updating vlan range " + vlanRange.getId()); + vlanRange.setIpRange(vlanRange.getIpRange().replace(currentStartIP+"-", newStartIP+"-").replace(currentEndIP, + newEndIP)); + _vlanDao.update(vlanRange.getId(), vlanRange); + + final boolean isRangeForSystemVM = checkIfVlanRangeIsForSystemVM(id); + if (ipv4) { + if (!updatePublicIPRange(newStartIP,currentStartIP,newEndIP,currentEndIP,vlanRange.getDataCenterId(),vlanRange.getId(), vlanRange.getNetworkId(), vlanRange.getPhysicalNetworkId(), isRangeForSystemVM)) { + throw new CloudRuntimeException("Failed to update IPv4 range. Please contact Cloud Support."); + } + } + return vlanRange; + } + }); + + } + private boolean checkIfVlanRangeIsForSystemVM(final long vlanId) { + List 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 recods. Please contact Cloud Support"); + } + } + return initialIsSystemVmValue; + } + + private void checkAllocatedIpsAreWithinVlanRange(List ips, String startIp, String endIp){ + // Check if the VLAN has any allocated public IPs + List 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()); + } + } + } + + private void checkGatewayOverlap(String startIp, String endIp, String gateway){ + if (NetUtils.ipRangesOverlap(startIp, endIp, gateway, gateway)) { + throw new InvalidParameterValueException("The gateway shouldn't overlap the new start/end ip " + + "addresses"); + } + } + @Override @DB public boolean deleteVlanAndPublicIpRange(final long userId, final long vlanDbId, final Account caller) { @@ -4404,6 +4560,51 @@ public List doInTransaction(final TransactionStatus status) { 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 forSystemVms) { + long newStartIPLong = NetUtils.ip2Long(newStartIP); + long newEndIPLong = NetUtils.ip2Long(newEndIP); + long currentStartIPLong = NetUtils.ip2Long(currentStartIP); + long currentEndIPLong = NetUtils.ip2Long(currentEndIP); + + List currentIPRange = new ArrayList<>(); + List newIPRange = new ArrayList<>(); + while (newStartIPLong<=newEndIPLong){ + newIPRange.add(newStartIPLong); + newStartIPLong++; + } + while (currentStartIPLong<=currentEndIPLong){ + currentIPRange.add(currentStartIPLong); + currentStartIPLong++; + } + + final List problemIps= Transaction.execute(new TransactionCallback>() { + + @Override + public List doInTransaction(final TransactionStatus status) { + final IPRangeConfig config = new IPRangeConfig(); + Vector configResult = new Vector<>(); + List iPAddressesToAdd = new ArrayList(newIPRange); + iPAddressesToAdd.removeAll(currentIPRange); + if (iPAddressesToAdd.size()>0){ + for(Long startIP : iPAddressesToAdd){ + configResult= config.savePublicIPRange(TransactionLegacy.currentTxn(), startIP, startIP, zoneId, vlanDbId, sourceNetworkid, physicalNetworkId, forSystemVms); + } + }else { + currentIPRange.removeAll(newIPRange); + if(currentIPRange.size()>0){ + for (Long startIP: currentIPRange){ + configResult= config.deletePublicIPRange(TransactionLegacy.currentTxn(), startIP, startIP, vlanDbId); + } + } + + } + return configResult; + } + }); + return problemIps != null && problemIps.size() == 0; + } + private void checkPublicIpRangeErrors(final long zoneId, final String vlanId, final String vlanGateway, final String vlanNetmask, final String startIP, final String endIP) { // Check that the start and end IPs are valid if (!NetUtils.isValidIp4(startIP)) { diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java index a3e9bb655940..73a87bf88e38 100644 --- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java +++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java @@ -242,6 +242,7 @@ import org.apache.cloudstack.api.command.admin.vlan.DeleteVlanIpRangeCmd; import org.apache.cloudstack.api.command.admin.vlan.ListVlanIpRangesCmd; import org.apache.cloudstack.api.command.admin.vlan.ReleasePublicIpRangeCmd; +import org.apache.cloudstack.api.command.admin.vlan.UpdateVlanIpRangeCmd; import org.apache.cloudstack.api.command.admin.vm.AddNicToVMCmdByAdmin; import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; import org.apache.cloudstack.api.command.admin.vm.DeployVMCmdByAdmin; @@ -2784,6 +2785,7 @@ public List> getCommands() { cmdList.add(RegisterCmd.class); cmdList.add(UpdateUserCmd.class); cmdList.add(CreateVlanIpRangeCmd.class); + cmdList.add(UpdateVlanIpRangeCmd.class); cmdList.add(DeleteVlanIpRangeCmd.class); cmdList.add(ListVlanIpRangesCmd.class); cmdList.add(DedicatePublicIpRangeCmd.class); diff --git a/server/src/main/java/com/cloud/test/IPRangeConfig.java b/server/src/main/java/com/cloud/test/IPRangeConfig.java index f35989102dd1..4cd76d249bd7 100644 --- a/server/src/main/java/com/cloud/test/IPRangeConfig.java +++ b/server/src/main/java/com/cloud/test/IPRangeConfig.java @@ -313,9 +313,9 @@ protected Vector deleteIPRange(String type, long podId, long zoneId, lon return problemIPs; } - private Vector deletePublicIPRange(TransactionLegacy txn, long startIP, long endIP, long vlanDbId) { - String deleteSql = "DELETE FROM `cloud`.`user_ip_address` WHERE public_ip_address = ? AND vlan_id = ?"; - String isPublicIPAllocatedSelectSql = "SELECT * FROM `cloud`.`user_ip_address` WHERE public_ip_address = ? AND vlan_id = ?"; + public Vector deletePublicIPRange(TransactionLegacy txn, long startIP, long endIP, long vlanDbId) { + String deleteSql = "DELETE FROM `cloud`.`user_ip_address` WHERE public_ip_address = ? AND vlan_db_id = ?"; + String isPublicIPAllocatedSelectSql = "SELECT * FROM `cloud`.`user_ip_address` WHERE public_ip_address = ? AND vlan_db_id = ?"; Vector problemIPs = new Vector(); Connection conn = null; @@ -329,9 +329,9 @@ private Vector deletePublicIPRange(TransactionLegacy txn, long startIP, try(PreparedStatement stmt = conn.prepareStatement(deleteSql); PreparedStatement isAllocatedStmt = conn.prepareStatement(isPublicIPAllocatedSelectSql);) { while (startIP <= endIP) { - if (!isPublicIPAllocated(startIP, vlanDbId, isAllocatedStmt)) { + if (!isPublicIPAllocated(NetUtils.long2Ip(startIP), vlanDbId, isAllocatedStmt)) { stmt.clearParameters(); - stmt.setLong(1, startIP); + stmt.setString(1, NetUtils.long2Ip(startIP)); stmt.setLong(2, vlanDbId); stmt.executeUpdate(); } @@ -379,21 +379,25 @@ private Vector deletePrivateIPRange(TransactionLegacy txn, long startIP, return problemIPs; } - private boolean isPublicIPAllocated(long ip, long vlanDbId, PreparedStatement stmt) { - try(ResultSet rs = stmt.executeQuery();) { - stmt.clearParameters(); - stmt.setLong(1, ip); - stmt.setLong(2, vlanDbId); - if (rs.next()) { - return (rs.getString("allocated") != null); - } else { - return false; - } - } - catch (SQLException ex) { - System.out.println(ex.getMessage()); - return true; - } + private boolean isPublicIPAllocated(String ip, long vlanDbId, PreparedStatement stmt) { + try{ + stmt.clearParameters(); + stmt.setString(1, ip); + stmt.setLong(2, vlanDbId); + try(ResultSet rs = stmt.executeQuery();) { + if (rs.next()) { + return (rs.getString("allocated") != null); + } else { + return false; + } + } + catch (SQLException ex) { + System.out.println(ex.getMessage()); + return true; + }}catch (SQLException ex) { + System.out.println(ex.getMessage()); + return true; + } } private boolean isPrivateIPAllocated(String ip, long podId, long zoneId, PreparedStatement stmt) { diff --git a/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java index b42996bb02b0..94b4ceae4398 100644 --- a/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java +++ b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java @@ -44,6 +44,7 @@ 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.vlan.UpdateVlanIpRangeCmd; 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; @@ -258,6 +259,17 @@ public Vlan createVlanAndPublicIpRange(CreateVlanIpRangeCmd cmd) throws Insuffic return null; } + /* (non-Javadoc) + * @see com.cloud.configuration.ConfigurationService#updateVlanAndPublicIpRange(org.apache.cloudstack.api + * .commands.UpdateVlanIpRangeCmd) + */ + @Override + public Vlan updateVlanAndPublicIpRange(UpdateVlanIpRangeCmd cmd) throws ConcurrentOperationException, + ResourceUnavailableException, ResourceAllocationException{ + // TODO Auto-generated method stub + return null; + } + /* (non-Javadoc) * @see com.cloud.configuration.ConfigurationService#markDefaultZone(java.lang.String, long, long) */ From aa1650bb85273164b018a923d6d3017ef884af6d Mon Sep 17 00:00:00 2001 From: kioie Date: Sun, 29 Mar 2020 09:41:59 +0300 Subject: [PATCH 02/14] Edited ConfigurationManagerImpl --- .../com/cloud/configuration/ConfigurationManagerImpl.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index a2c9c8e79ab3..362fb73c81ef 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -26,10 +26,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; -<<<<<<< HEAD:server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java -======= import java.util.Comparator; ->>>>>>> Added Logic to update the user_ip_address table:server/src/com/cloud/configuration/ConfigurationManagerImpl.java import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -43,13 +40,8 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; - -<<<<<<< HEAD:server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java -======= import com.cloud.network.IpAddress; import com.google.common.collect.Sets; - ->>>>>>> Added Logic to update the user_ip_address table:server/src/com/cloud/configuration/ConfigurationManagerImpl.java import org.apache.cloudstack.acl.SecurityChecker; import org.apache.cloudstack.affinity.AffinityGroup; import org.apache.cloudstack.affinity.AffinityGroupService; From 5d572bbeb88a236b840048d511c3e16e949a775c Mon Sep 17 00:00:00 2001 From: kioie Date: Mon, 6 Jul 2020 13:06:21 +0300 Subject: [PATCH 03/14] Refactor UpdateVlanIpRangeCmd location --- .../cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmd.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename api/src/{ => main/java}/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmd.java (100%) diff --git a/api/src/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmd.java similarity index 100% rename from api/src/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmd.java rename to api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmd.java From 0a76ff467a6d3843e20da138707ab87ba448aedc Mon Sep 17 00:00:00 2001 From: kioie Date: Mon, 13 Jul 2020 13:44:16 +0300 Subject: [PATCH 04/14] Checkstyle corrections --- .../ConfigurationManagerImpl.java | 66 ++++++++++--------- .../java/com/cloud/test/IPRangeConfig.java | 21 +++--- 2 files changed, 45 insertions(+), 42 deletions(-) diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index 362fb73c81ef..45d783713c63 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -40,8 +40,7 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; -import com.cloud.network.IpAddress; -import com.google.common.collect.Sets; + import org.apache.cloudstack.acl.SecurityChecker; import org.apache.cloudstack.affinity.AffinityGroup; import org.apache.cloudstack.affinity.AffinityGroupService; @@ -165,6 +164,7 @@ import com.cloud.gpu.GPU; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.network.IpAddress; import com.cloud.network.IpAddressManager; import com.cloud.network.Network; import com.cloud.network.Network.Capability; @@ -1775,7 +1775,6 @@ private void checkZoneParameters(final String zoneName, final String dns1, final } } - private void checkIpRange(final String startIp, final String endIp, final String cidrAddress, final long cidrSize) { //Checking not null for start IP as well. Previously we assumed to be not null always. //But the check is required for the change in updatePod API. @@ -4082,7 +4081,7 @@ public VlanVO doInTransaction(final TransactionStatus status) { @Override public Vlan updateVlanAndPublicIpRange(UpdateVlanIpRangeCmd cmd) throws ConcurrentOperationException, - ResourceUnavailableException,ResourceAllocationException{ + ResourceUnavailableException,ResourceAllocationException { return updateVlanAndPublicIpRange(cmd.getId(), cmd.getStartIp(),cmd.getEndIp(), cmd.getGateway(),cmd.getNetmask()); @@ -4094,7 +4093,7 @@ public Vlan updateVlanAndPublicIpRange(UpdateVlanIpRangeCmd cmd) throws Concurre public Vlan updateVlanAndPublicIpRange(final long id, String startIp, String endIp, String gateway, - String netmask) throws ConcurrentOperationException{ + String netmask) throws ConcurrentOperationException { VlanVO vlanRange = _vlanDao.findById(id); if (vlanRange == null) { @@ -4110,15 +4109,15 @@ public Vlan updateVlanAndPublicIpRange(final long id, String startIp, } final String[] existingVlanIPRangeArray = vlanRange.getIpRange().split("-"); - final String currentStartIP= existingVlanIPRangeArray[0]; + final String currentStartIP = existingVlanIPRangeArray[0]; final String currentEndIP = existingVlanIPRangeArray [1]; - if(startIp == null){ - startIp= currentStartIP; + if(startIp == null) { + startIp = currentStartIP; } - if(endIp == null){ - endIp= currentEndIP; + if(endIp == null) { + endIp = currentEndIP; } final List ips = _publicIpAddressDao.listByVlanId(id); @@ -4136,8 +4135,8 @@ public Vlan updateVlanAndPublicIpRange(final long id, String startIp, VlanVO range; try { - final String newStartIP= startIp; - final String newEndIP= endIp; + final String newStartIP = startIp; + final String newEndIP = endIp; range = _vlanDao.acquireInLockTable(id, 30); if (range == null) { @@ -4153,19 +4152,20 @@ public Vlan updateVlanAndPublicIpRange(final long id, String startIp, } 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 { + } finally { _vlanDao.releaseFromLockTable(id); } return vlanRange; } private VlanVO commitUpdateVlanAndIpRange(final Long id, final String newStartIP, final String newEndIP,final String currentStartIP, final String currentEndIP, final boolean ipv4) { + return Transaction.execute(new TransactionCallback() { @Override public VlanVO doInTransaction(final TransactionStatus status) { VlanVO vlanRange = _vlanDao.findById(id); s_logger.debug("Updating vlan range " + vlanRange.getId()); - vlanRange.setIpRange(vlanRange.getIpRange().replace(currentStartIP+"-", newStartIP+"-").replace(currentEndIP, + vlanRange.setIpRange(vlanRange.getIpRange().replace(currentStartIP + "-" , newStartIP + "-" ).replace(currentEndIP, newEndIP)); _vlanDao.update(vlanRange.getId(), vlanRange); @@ -4180,46 +4180,47 @@ public VlanVO doInTransaction(final TransactionStatus status) { }); } + private boolean checkIfVlanRangeIsForSystemVM(final long vlanId) { List existingPublicIPs = _publicIpAddressDao.listByVlanId(vlanId); boolean initialIsSystemVmValue = existingPublicIPs.get(0).isForSystemVms(); - for(IPAddressVO existingIPs : existingPublicIPs){ - if(initialIsSystemVmValue != existingIPs.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 recods. Please contact Cloud Support"); } } return initialIsSystemVmValue; } - private void checkAllocatedIpsAreWithinVlanRange(List ips, String startIp, String endIp){ - // Check if the VLAN has any allocated public IPs + private void checkAllocatedIpsAreWithinVlanRange(List ips, String startIp, String endIp) { + List listAllocatedIPs = new ArrayList<>(); for (final IPAddressVO ip : ips) { - if (ip.getState()== IpAddress.State.Allocated){ + if (ip.getState() == IpAddress.State.Allocated) { listAllocatedIPs.add(ip); } } Collections.sort(listAllocatedIPs, Comparator.comparing(IPAddressVO::getAddress)); - for (IPAddressVO allocatedIP : listAllocatedIPs){ + 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()); + 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()); + 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()); } } } - private void checkGatewayOverlap(String startIp, String endIp, String gateway){ + private void checkGatewayOverlap(String startIp, String endIp, String gateway) { if (NetUtils.ipRangesOverlap(startIp, endIp, gateway, gateway)) { - throw new InvalidParameterValueException("The gateway shouldn't overlap the new start/end ip " + - "addresses"); + throw new InvalidParameterValueException("The gateway shouldn't overlap the new start/end ip " + + "addresses"); } } @@ -4276,7 +4277,8 @@ public boolean deleteVlanAndPublicIpRange(final long userId, final long vlanDbId throw new InvalidParameterValueException("Can't delete account specific vlan " + vlanDbId + " as ip " + ip + " belonging to the range has firewall rules applied. Cleanup the rules first"); } - if (ip.getAllocatedTime() != null) {// This means IP is allocated + if (ip.getAllocatedTime() != null) { + // This means IP is allocated // release public ip address here success = _ipAddrMgr.disassociatePublicIpAddress(ip.getId(), userId, caller); } diff --git a/server/src/main/java/com/cloud/test/IPRangeConfig.java b/server/src/main/java/com/cloud/test/IPRangeConfig.java index 4cd76d249bd7..79843600967a 100644 --- a/server/src/main/java/com/cloud/test/IPRangeConfig.java +++ b/server/src/main/java/com/cloud/test/IPRangeConfig.java @@ -323,10 +323,10 @@ public Vector deletePublicIPRange(TransactionLegacy txn, long startIP, l conn = txn.getConnection(); } catch (SQLException e) { - System.out.println("deletePublicIPRange. Exception: " +e.getMessage()); + System.out.println("deletePublicIPRange. Exception: " + e.getMessage()); return null; } - try(PreparedStatement stmt = conn.prepareStatement(deleteSql); + try (PreparedStatement stmt = conn.prepareStatement(deleteSql); PreparedStatement isAllocatedStmt = conn.prepareStatement(isPublicIPAllocatedSelectSql);) { while (startIP <= endIP) { if (!isPublicIPAllocated(NetUtils.long2Ip(startIP), vlanDbId, isAllocatedStmt)) { @@ -334,14 +334,14 @@ public Vector deletePublicIPRange(TransactionLegacy txn, long startIP, l stmt.setString(1, NetUtils.long2Ip(startIP)); stmt.setLong(2, vlanDbId); stmt.executeUpdate(); - } + } else { problemIPs.add(NetUtils.long2Ip(startIP)); } startIP += 1; } - }catch (Exception ex) { - System.out.println("deletePublicIPRange. Exception: " +ex.getMessage()); + } catch (Exception ex) { + System.out.println("deletePublicIPRange. Exception: " + ex.getMessage()); return null; } @@ -372,7 +372,7 @@ private Vector deletePrivateIPRange(TransactionLegacy txn, long startIP, System.out.println("deletePrivateIPRange. Exception: " + e.getMessage()); printError("deletePrivateIPRange. Exception: " + e.getMessage()); } - }catch (SQLException e) { + } catch (SQLException e) { System.out.println("deletePrivateIPRange. Exception: " + e.getMessage()); printError("deletePrivateIPRange. Exception: " + e.getMessage()); } @@ -380,21 +380,22 @@ private Vector deletePrivateIPRange(TransactionLegacy txn, long startIP, } private boolean isPublicIPAllocated(String ip, long vlanDbId, PreparedStatement stmt) { - try{ + try { stmt.clearParameters(); stmt.setString(1, ip); stmt.setLong(2, vlanDbId); - try(ResultSet rs = stmt.executeQuery();) { + try (ResultSet rs = stmt.executeQuery()) { if (rs.next()) { return (rs.getString("allocated") != null); } else { return false; } - } + } catch (SQLException ex) { System.out.println(ex.getMessage()); return true; - }}catch (SQLException ex) { + } + } catch (SQLException ex) { System.out.println(ex.getMessage()); return true; } From a49dc954e8ca249946085af48a7107c8549c2d98 Mon Sep 17 00:00:00 2001 From: kioie Date: Mon, 13 Jul 2020 18:27:46 +0300 Subject: [PATCH 05/14] Mock updateVlanAndPublicIpRange --- .../java/com/cloud/vpc/MockConfigurationManagerImpl.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java index 94b4ceae4398..0bf18233cb60 100644 --- a/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java +++ b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java @@ -514,6 +514,14 @@ public Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physica return null; } + /* (non-Javadoc) + * @see com.cloud.configuration.ConfigurationManager#updateVlanAndPublicIpRange(long, java.lang.String, java.lang.String, java.lang.String, java.lang.String) + */ + @Override + public Vlan updateVlanAndPublicIpRange(long id, String startIp, String endIp, String gateway, String netmask) throws ConcurrentOperationException { + return null; + } + /* (non-Javadoc) * @see com.cloud.configuration.ConfigurationManager#createDefaultSystemNetworks(long) */ From d5ee6b991b2a9845bd6695d4d94be1e05b9db9ab Mon Sep 17 00:00:00 2001 From: kioie Date: Thu, 22 Oct 2020 08:06:32 +0300 Subject: [PATCH 06/14] Changes: UpdateVlanIpRangeCmd - changed since to 4.15.0 ConfigurationService - updated Javadoc ConfigurationManager - Updated Javadoc --- .../configuration/ConfigurationService.java | 16 +++++----------- .../command/admin/vlan/UpdateVlanIpRangeCmd.java | 2 +- .../configuration/ConfigurationManager.java | 11 +++++++++-- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/api/src/main/java/com/cloud/configuration/ConfigurationService.java b/api/src/main/java/com/cloud/configuration/ConfigurationService.java index 98fea0ecab77..39b4c9898e7f 100644 --- a/api/src/main/java/com/cloud/configuration/ConfigurationService.java +++ b/api/src/main/java/com/cloud/configuration/ConfigurationService.java @@ -274,18 +274,12 @@ Vlan createVlanAndPublicIpRange(CreateVlanIpRangeCmd cmd) throws InsufficientCap ResourceAllocationException; /** - * Updates the IP address Range for the VLAN on the database, a - * + * Updates the IP address Range for the VLAN on the database * @param cmd - * @param vlanId - * @param gateway - * @param startIP - * @param endIP - * @param netmask - * @throws com.cloud.exception.ConcurrentOperationException - * @throws com.cloud.exception.ResourceUnavailableException - * @throws com.cloud.exception.ResourceAllocationException - * @return The updated Vlan object + * @return + * @throws ConcurrentOperationException + * @throws ResourceUnavailableException + * @throws ResourceAllocationException */ Vlan updateVlanAndPublicIpRange(UpdateVlanIpRangeCmd cmd) throws ConcurrentOperationException, ResourceUnavailableException, ResourceAllocationException; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmd.java index b5e6aff42cd4..1b763406613d 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmd.java @@ -35,7 +35,7 @@ import com.cloud.utils.net.NetUtils; @APICommand(name = UpdateVlanIpRangeCmd.APINAME, description = "Updates a VLAN IP range.", responseObject = - VlanIpRangeResponse.class, since = "4.13.0", + VlanIpRangeResponse.class, since = "4.15.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) public class UpdateVlanIpRangeCmd extends BaseAsyncCmd { diff --git a/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java b/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java index 3fc5ab42c122..5e36a796fd43 100644 --- a/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java +++ b/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java @@ -220,8 +220,15 @@ Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetwor String vlanGateway, String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, Account vlanOwner, String startIPv6, String endIPv6, String vlanIp6Gateway, String vlanIp6Cidr) throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException; - /* (non-Javadoc) - * @see com.cloud.configuration.ConfigurationManager#updateVlanAndPublicIpRange(long,String,String,String,String) + /** + * Updates the IP address Range for the VLAN and the Public IP + * @param id + * @param startIp + * @param endIp + * @param gateway + * @param netmask + * @return + * @throws ConcurrentOperationException */ Vlan updateVlanAndPublicIpRange(long id, String startIp, String endIp, String gateway, String netmask) throws ConcurrentOperationException; From a765191602fe972f311f0cabe14b7fefc688b33b Mon Sep 17 00:00:00 2001 From: kioie Date: Fri, 23 Oct 2020 11:16:33 +0300 Subject: [PATCH 07/14] Changes: Added Unit test --- .../configuration/ConfigurationService.java | 2 +- .../admin/vlan/UpdateVlanIpRangeCmdTest.java | 62 +++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 api/src/test/java/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmdTest.java diff --git a/api/src/main/java/com/cloud/configuration/ConfigurationService.java b/api/src/main/java/com/cloud/configuration/ConfigurationService.java index 39b4c9898e7f..ee41fa7c2b84 100644 --- a/api/src/main/java/com/cloud/configuration/ConfigurationService.java +++ b/api/src/main/java/com/cloud/configuration/ConfigurationService.java @@ -276,7 +276,7 @@ Vlan createVlanAndPublicIpRange(CreateVlanIpRangeCmd cmd) throws InsufficientCap /** * Updates the IP address Range for the VLAN on the database * @param cmd - * @return + * @return The Updated Vlan Object * @throws ConcurrentOperationException * @throws ResourceUnavailableException * @throws ResourceAllocationException diff --git a/api/src/test/java/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmdTest.java new file mode 100644 index 000000000000..41ba3debfe28 --- /dev/null +++ b/api/src/test/java/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmdTest.java @@ -0,0 +1,62 @@ +package org.apache.cloudstack.api.command.admin.vlan; + +import junit.framework.TestCase; + +import org.apache.cloudstack.api.ResponseGenerator; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.VlanIpRangeResponse; +import org.junit.Test; +import org.mockito.Mockito; + +import com.cloud.configuration.ConfigurationService; +import com.cloud.dc.Vlan; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; + +public class UpdateVlanIpRangeCmdTest extends TestCase { + + private UpdateVlanIpRangeCmd updateVlanIpRangeCmd; + private ResponseGenerator responseGenerator; + + @Test + public void testUpdateSuccess() throws Exception { + + ConfigurationService configService = Mockito.mock(ConfigurationService.class); + Vlan result = Mockito.mock(Vlan.class); + + responseGenerator = Mockito.mock(ResponseGenerator.class); + updateVlanIpRangeCmd = new UpdateVlanIpRangeCmd(); + + Mockito.when(configService.updateVlanAndPublicIpRange(updateVlanIpRangeCmd)).thenReturn(result); + updateVlanIpRangeCmd._configService = configService; + + VlanIpRangeResponse ipRes = Mockito.mock(VlanIpRangeResponse.class); + Mockito.when(responseGenerator.createVlanIpRangeResponse(result)).thenReturn(ipRes); + + updateVlanIpRangeCmd._responseGenerator = responseGenerator; + try { + updateVlanIpRangeCmd.execute(); + } catch (ServerApiException ex) { + assertEquals("Failed to Update vlan ip range", ex.getMessage()); + } + } + + @Test + public void testUpdateFailure() throws ResourceAllocationException, ResourceUnavailableException { + + ConfigurationService configService = Mockito.mock(ConfigurationService.class); + + responseGenerator = Mockito.mock(ResponseGenerator.class); + updateVlanIpRangeCmd = new UpdateVlanIpRangeCmd(); + updateVlanIpRangeCmd._configService = configService; + + Mockito.when(configService.updateVlanAndPublicIpRange(updateVlanIpRangeCmd)).thenReturn(null); + + try { + updateVlanIpRangeCmd.execute(); + } catch (ServerApiException ex) { + assertEquals("Failed to Update vlan ip range", ex.getMessage()); + } + + } +} \ No newline at end of file From 84828d4695da9f94dc8e496930c499119ca5d052 Mon Sep 17 00:00:00 2001 From: kioie Date: Fri, 23 Oct 2020 15:43:45 +0300 Subject: [PATCH 08/14] Add license --- .../admin/vlan/UpdateVlanIpRangeCmdTest.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/api/src/test/java/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmdTest.java index 41ba3debfe28..280acbda6897 100644 --- a/api/src/test/java/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmdTest.java +++ b/api/src/test/java/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmdTest.java @@ -1,3 +1,19 @@ +// 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 junit.framework.TestCase; From 4d417ea57fd14bea873c04a7344bad1420d1f2ac Mon Sep 17 00:00:00 2001 From: dahn Date: Tue, 10 Nov 2020 21:26:07 +0100 Subject: [PATCH 09/14] Update server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java --- .../java/com/cloud/configuration/ConfigurationManagerImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index 45d783713c63..f2718235310b 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -4158,6 +4158,7 @@ public Vlan updateVlanAndPublicIpRange(final long id, String startIp, return vlanRange; } + private VlanVO commitUpdateVlanAndIpRange(final Long id, final String newStartIP, final String newEndIP,final String currentStartIP, final String currentEndIP, final boolean ipv4) { return Transaction.execute(new TransactionCallback() { From a02022503fb24b9df3cd55ecbb5e797f1a6d0fef Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Tue, 7 Sep 2021 09:17:19 +0200 Subject: [PATCH 10/14] fix some bugs in #5411 and add support for ipv6 and forsystemvms --- .../admin/vlan/UpdateVlanIpRangeCmd.java | 45 +++- .../configuration/ConfigurationManager.java | 12 - .../ConfigurationManagerImpl.java | 254 +++++++++++++----- .../java/com/cloud/test/IPRangeConfig.java | 29 ++ .../vpc/MockConfigurationManagerImpl.java | 8 - 5 files changed, 251 insertions(+), 97 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmd.java index 1b763406613d..8d07f579ba91 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmd.java @@ -16,6 +16,7 @@ // under the License. package org.apache.cloudstack.api.command.admin.vlan; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -35,8 +36,9 @@ import com.cloud.utils.net.NetUtils; @APICommand(name = UpdateVlanIpRangeCmd.APINAME, description = "Updates a VLAN IP range.", responseObject = - VlanIpRangeResponse.class, since = "4.15.0", - requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) + VlanIpRangeResponse.class, since = "4.16.0", + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + authorized = {RoleType.Admin}) public class UpdateVlanIpRangeCmd extends BaseAsyncCmd { public static final String APINAME = "updateVlanIpRange"; @@ -51,10 +53,6 @@ public class UpdateVlanIpRangeCmd extends BaseAsyncCmd { description = "the UUID of the VLAN IP range") private Long id; - @Parameter(name = ApiConstants.END_IP, type = CommandType.STRING, - description = "the ending IP address in the VLAN IP range") - private String endIp; - @Parameter(name = ApiConstants.GATEWAY, type = CommandType.STRING, description = "the gateway of the VLAN IP range") private String gateway; @@ -64,14 +62,24 @@ public class UpdateVlanIpRangeCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.START_IP, type = CommandType.STRING, description = "the beginning IP address in the VLAN IP range") private String startIp; + @Parameter(name = ApiConstants.END_IP, type = CommandType.STRING, + description = "the ending IP address in the VLAN IP range") + private String endIp; + @Parameter(name = ApiConstants.START_IPV6, type = CommandType.STRING, description = "the beginning IPv6 address in the IPv6 network range") private String startIpv6; @Parameter(name = ApiConstants.END_IPV6, type = CommandType.STRING, description = "the ending IPv6 address in the IPv6 network range") private String endIpv6; - @Parameter(name = ApiConstants.VLAN, type = CommandType.INTEGER, description = "Optional. the vlan the ip range sits on") - private Integer vlan; + @Parameter(name = ApiConstants.IP6_GATEWAY, type = CommandType.STRING, description = "the gateway of the IPv6 network") + private String ip6Gateway; + + @Parameter(name = ApiConstants.IP6_CIDR, type = CommandType.STRING, description = "the CIDR of IPv6 network, must be at least /64") + private String ip6Cidr; + + @Parameter(name = ApiConstants.FOR_SYSTEM_VMS, type = CommandType.BOOLEAN, description = "true if IP range is set to system vms, false if not") + private Boolean forSystemVms; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -110,8 +118,22 @@ public String getEndIpv6() { return NetUtils.standardizeIp6Address(endIpv6); } - public Integer getVlan() { - return vlan; + public String getIp6Gateway() { + if (ip6Gateway == null) { + return null; + } + return NetUtils.standardizeIp6Address(ip6Gateway); + } + + public String getIp6Cidr() { + if (ip6Cidr == null) { + return null; + } + return NetUtils.standardizeIp6Cidr(ip6Cidr); + } + + public Boolean isForSystemVms() { + return forSystemVms; } ///////////////////////////////////////////////////// @@ -125,7 +147,8 @@ public String getEventType() { @Override public String getEventDescription() { - return "Update vlan ip range " + getId() + " [StartIp=" + getStartIp() + ", EndIp=" + getEndIp() + ", vlan=" + getVlan() + ", netmask=" + getNetmask() + ']'; + return "Update vlan ip range " + getId() + " [StartIp=" + getStartIp() + ", EndIp=" + getEndIp() + ", gateway=" + getGateway() + ", netmask=" + getNetmask() + + ", StartIpv6=" + getStartIpv6() + ", EndIpv6=" + getEndIpv6() + ", ip6gateway=" + getIp6Gateway() + ", ip6cidr=" + getIp6Cidr() + ']'; } diff --git a/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java b/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java index bb35783b3895..66772002b5f8 100644 --- a/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java +++ b/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java @@ -220,18 +220,6 @@ Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetwor String vlanGateway, String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, Account vlanOwner, String startIPv6, String endIPv6, String vlanIp6Gateway, String vlanIp6Cidr) throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException; - /** - * Updates the IP address Range for the VLAN and the Public IP - * @param id - * @param startIp - * @param endIp - * @param gateway - * @param netmask - * @return - * @throws ConcurrentOperationException - */ - Vlan updateVlanAndPublicIpRange(long id, String startIp, String endIp, String gateway, String netmask) throws ConcurrentOperationException; - void createDefaultSystemNetworks(long zoneId) throws ConcurrentOperationException; /** diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index aeb2059502f9..11b3d0fec5d5 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -41,6 +41,7 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.googlecode.ipv6.IPv6Address; import org.apache.cloudstack.acl.SecurityChecker; import org.apache.cloudstack.affinity.AffinityGroup; import org.apache.cloudstack.affinity.AffinityGroupService; @@ -180,6 +181,8 @@ import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.TrafficType; import com.cloud.network.PhysicalNetwork; +import com.cloud.network.UserIpv6Address; +import com.cloud.network.UserIpv6AddressVO; import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; @@ -189,6 +192,7 @@ import com.cloud.network.dao.PhysicalNetworkTrafficTypeDao; import com.cloud.network.dao.PhysicalNetworkTrafficTypeVO; import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.network.dao.UserIpv6AddressDao; import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.vpc.VpcManager; import com.cloud.offering.DiskOffering; @@ -403,7 +407,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati HostTagsDao hostTagDao; @Inject StoragePoolTagsDao storagePoolTagDao; - + @Inject + UserIpv6AddressDao _ipv6Dao; // FIXME - why don't we have interface for DataCenterLinkLocalIpAddressDao? @Inject @@ -4232,8 +4237,8 @@ public VlanVO doInTransaction(final TransactionStatus status) { public Vlan updateVlanAndPublicIpRange(UpdateVlanIpRangeCmd cmd) throws ConcurrentOperationException, ResourceUnavailableException,ResourceAllocationException { - return updateVlanAndPublicIpRange(cmd.getId(), cmd.getStartIp(),cmd.getEndIp(), - cmd.getGateway(),cmd.getNetmask()); + return updateVlanAndPublicIpRange(cmd.getId(), cmd.getStartIp(),cmd.getEndIp(), cmd.getGateway(),cmd.getNetmask(), + cmd.getStartIpv6(), cmd.getEndIpv6(), cmd.getIp6Gateway(), cmd.getIp6Cidr(), cmd.isForSystemVms()); } @DB @@ -4242,93 +4247,172 @@ public Vlan updateVlanAndPublicIpRange(UpdateVlanIpRangeCmd cmd) throws Concurre public Vlan updateVlanAndPublicIpRange(final long id, String startIp, String endIp, String gateway, - String netmask) throws ConcurrentOperationException { + 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."); } - if (gateway == null) { - gateway = vlanRange.getVlanGateway(); + 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."); + } } - if (netmask == null) { - netmask = vlanRange.getVlanNetmask(); + if (forSystemVms != null && VlanType.DirectAttached.equals(vlanRange.getVlanType())) { + throw new InvalidParameterValueException("forSystemVms is not available for this IP range with vlan type: " + VlanType.DirectAttached); } + 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()); + } - final String[] existingVlanIPRangeArray = vlanRange.getIpRange().split("-"); - final String currentStartIP = existingVlanIPRangeArray[0]; - final String currentEndIP = existingVlanIPRangeArray [1]; + if (gateway == null) { + gateway = vlanRange.getVlanGateway(); + } - if(startIp == null) { - startIp = currentStartIP; - } + if (netmask == null) { + netmask = vlanRange.getVlanNetmask(); + } - if(endIp == null) { - endIp = currentEndIP; - } + final String[] existingVlanIPRangeArray = vlanRange.getIpRange().split("-"); + final String currentStartIP = existingVlanIPRangeArray[0]; + final String currentEndIP = existingVlanIPRangeArray[1]; - final List ips = _publicIpAddressDao.listByVlanId(id); - checkAllocatedIpsAreWithinVlanRange(ips,startIp,endIp); + if (startIp == null) { + startIp = currentStartIP; + } - final String cidr = NetUtils.ipAndNetMaskToCidr(gateway, netmask); - final String cidrAddress = getCidrAddress(cidr); - final long cidrSize = getCidrSize(cidr); + if (endIp == null) { + endIp = currentEndIP; + } - checkIpRange(currentStartIP,currentEndIP,cidrAddress,cidrSize); + 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(startIp, endIp, cidrAddress, cidrSize); + checkIpRange(currentStartIP, currentEndIP, cidrAddress, cidrSize); + if (startIp != currentStartIP || endIp != currentEndIP) { + checkIpRange(startIp, endIp, cidrAddress, cidrSize); + } - checkGatewayOverlap(startIp,endIp,gateway); + checkGatewayOverlap(startIp, endIp, gateway); - VlanVO range; - try { - final String newStartIP = startIp; - final String newEndIP = endIp; + final List ips = _publicIpAddressDao.listByVlanId(id); + checkAllocatedIpsAreWithinVlanRange(ips, startIp, endIp, forSystemVms); - range = _vlanDao.acquireInLockTable(id, 30); - if (range == null) { - throw new CloudRuntimeException("Unable to acquire vlan configuration: " + id); + 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, 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 (s_logger.isDebugEnabled()) { - s_logger.debug("lock vlan " + id + " is acquired"); + 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()); - commitUpdateVlanAndIpRange(id, newStartIP, newEndIP, currentStartIP, currentEndIP,true); + final String[] existingVlanIPRangeArray = vlanRange.getIp6Range().split("-"); + final String currentStartIPv6 = existingVlanIPRangeArray[0]; + final String currentEndIPv6 = existingVlanIPRangeArray[1]; - } 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 (startIpv6 == null) { + startIpv6 = currentStartIPv6; + } + if (endIpv6 == null) { + endIpv6 = currentEndIPv6; + } + if (startIpv6 != currentStartIPv6 || endIpv6 != currentEndIPv6) { + _networkModel.checkIp6Parameters(startIpv6, endIpv6, ip6Gateway, ip6Cidr); + final List 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, null); + + } 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 vlanRange; + 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) { + private VlanVO commitUpdateVlanAndIpRange(final Long id, final String newStartIP, final String newEndIP, final String currentStartIP, final String currentEndIP, final boolean ipv4, final Boolean forSystemvms) { return Transaction.execute(new TransactionCallback() { @Override public VlanVO doInTransaction(final TransactionStatus status) { VlanVO vlanRange = _vlanDao.findById(id); s_logger.debug("Updating vlan range " + vlanRange.getId()); - vlanRange.setIpRange(vlanRange.getIpRange().replace(currentStartIP + "-" , newStartIP + "-" ).replace(currentEndIP, - newEndIP)); - _vlanDao.update(vlanRange.getId(), vlanRange); - - final boolean isRangeForSystemVM = checkIfVlanRangeIsForSystemVM(id); if (ipv4) { - if (!updatePublicIPRange(newStartIP,currentStartIP,newEndIP,currentEndIP,vlanRange.getDataCenterId(),vlanRange.getId(), vlanRange.getNetworkId(), vlanRange.getPhysicalNetworkId(), isRangeForSystemVM)) { + vlanRange.setIpRange(newStartIP + "-" + newEndIP); + _vlanDao.update(vlanRange.getId(), vlanRange); + final Boolean isRangeForSystemVM = checkIfVlanRangeIsForSystemVM(id); + 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) { @@ -4336,13 +4420,13 @@ private boolean checkIfVlanRangeIsForSystemVM(final long 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 recods. Please contact Cloud Support"); + 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 ips, String startIp, String endIp) { + private void checkAllocatedIpsAreWithinVlanRange(List ips, String startIp, String endIp, Boolean forSystemVms) { List listAllocatedIPs = new ArrayList<>(); for (final IPAddressVO ip : ips) { @@ -4364,6 +4448,36 @@ private void checkAllocatedIpsAreWithinVlanRange(List ips, String s + "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 ips, String startIpv6, String endIpv6) { + + List 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()); + } } } @@ -4708,7 +4822,7 @@ public List doInTransaction(final TransactionStatus status) { } @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 forSystemVms) { + 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) { long newStartIPLong = NetUtils.ip2Long(newStartIP); long newEndIPLong = NetUtils.ip2Long(newEndIP); long currentStartIPLong = NetUtils.ip2Long(currentStartIP); @@ -4716,35 +4830,43 @@ protected boolean updatePublicIPRange(final String newStartIP, final String curr List currentIPRange = new ArrayList<>(); List newIPRange = new ArrayList<>(); - while (newStartIPLong<=newEndIPLong){ + while (newStartIPLong <= newEndIPLong) { newIPRange.add(newStartIPLong); newStartIPLong++; } - while (currentStartIPLong<=currentEndIPLong){ + while (currentStartIPLong <= currentEndIPLong) { currentIPRange.add(currentStartIPLong); currentStartIPLong++; } - final List problemIps= Transaction.execute(new TransactionCallback>() { + final List problemIps = Transaction.execute(new TransactionCallback>() { @Override public List doInTransaction(final TransactionStatus status) { final IPRangeConfig config = new IPRangeConfig(); Vector configResult = new Vector<>(); - List iPAddressesToAdd = new ArrayList(newIPRange); - iPAddressesToAdd.removeAll(currentIPRange); - if (iPAddressesToAdd.size()>0){ - for(Long startIP : iPAddressesToAdd){ - configResult= config.savePublicIPRange(TransactionLegacy.currentTxn(), startIP, startIP, zoneId, vlanDbId, sourceNetworkid, physicalNetworkId, forSystemVms); + List ipAddressesToAdd = new ArrayList(newIPRange); + ipAddressesToAdd.removeAll(currentIPRange); + if (ipAddressesToAdd.size() > 0) { + for (Long startIP : ipAddressesToAdd) { + configResult.addAll(config.savePublicIPRange(TransactionLegacy.currentTxn(), startIP, startIP, zoneId, vlanDbId, sourceNetworkid, physicalNetworkId, forSystemVms != null ? forSystemVms : isRangeForSystemVM)); } - }else { - currentIPRange.removeAll(newIPRange); - if(currentIPRange.size()>0){ - for (Long startIP: currentIPRange){ - configResult= config.deletePublicIPRange(TransactionLegacy.currentTxn(), startIP, startIP, vlanDbId); + } + List ipAddressesToDelete = new ArrayList(currentIPRange); + ipAddressesToDelete.removeAll(newIPRange); + if (ipAddressesToDelete.size() > 0) { + for (Long startIP : ipAddressesToDelete) { + configResult.addAll(config.deletePublicIPRange(TransactionLegacy.currentTxn(), startIP, startIP, vlanDbId)); + } + } + if (forSystemVms != null && isRangeForSystemVM != forSystemVms) { + List ipAddressesToUpdate = new ArrayList(currentIPRange); + ipAddressesToUpdate.removeAll(ipAddressesToDelete); + if (ipAddressesToUpdate.size() > 0) { + for (Long startIP : ipAddressesToUpdate) { + configResult.addAll(config.updatePublicIPRange(TransactionLegacy.currentTxn(), startIP, startIP, vlanDbId, forSystemVms)); } } - } return configResult; } diff --git a/server/src/main/java/com/cloud/test/IPRangeConfig.java b/server/src/main/java/com/cloud/test/IPRangeConfig.java index 79843600967a..22ebb56963a1 100644 --- a/server/src/main/java/com/cloud/test/IPRangeConfig.java +++ b/server/src/main/java/com/cloud/test/IPRangeConfig.java @@ -313,6 +313,35 @@ protected Vector deleteIPRange(String type, long podId, long zoneId, lon return problemIPs; } + public Vector updatePublicIPRange(TransactionLegacy txn, long startIP, long endIP, long vlanDbId, boolean forSystemvms) { + String updateSql = "UPDATE `cloud`.`user_ip_address` SET forsystemvms = ? WHERE public_ip_address = ? AND vlan_db_id = ?"; + + Vector problemIPs = new Vector(); + Connection conn = null; + try { + conn = txn.getConnection(); + } + catch (SQLException e) { + System.out.println("updatePublicIPRange. Exception: " + e.getMessage()); + return null; + } + try (PreparedStatement stmt = conn.prepareStatement(updateSql);) { + while (startIP <= endIP) { + stmt.clearParameters(); + stmt.setBoolean(1, forSystemvms); + stmt.setString(2, NetUtils.long2Ip(startIP)); + stmt.setLong(3, vlanDbId); + stmt.executeUpdate(); + startIP += 1; + } + } catch (Exception ex) { + System.out.println("updatePublicIPRange. Exception: " + ex.getMessage()); + return null; + } + + return problemIPs; + } + public Vector deletePublicIPRange(TransactionLegacy txn, long startIP, long endIP, long vlanDbId) { String deleteSql = "DELETE FROM `cloud`.`user_ip_address` WHERE public_ip_address = ? AND vlan_db_id = ?"; String isPublicIPAllocatedSelectSql = "SELECT * FROM `cloud`.`user_ip_address` WHERE public_ip_address = ? AND vlan_db_id = ?"; diff --git a/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java index 3189cf546eeb..d6dbee844b14 100644 --- a/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java +++ b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java @@ -514,14 +514,6 @@ public Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physica return null; } - /* (non-Javadoc) - * @see com.cloud.configuration.ConfigurationManager#updateVlanAndPublicIpRange(long, java.lang.String, java.lang.String, java.lang.String, java.lang.String) - */ - @Override - public Vlan updateVlanAndPublicIpRange(long id, String startIp, String endIp, String gateway, String netmask) throws ConcurrentOperationException { - return null; - } - /* (non-Javadoc) * @see com.cloud.configuration.ConfigurationManager#createDefaultSystemNetworks(long) */ From e56eaea921302ed575bf639511dac6b2df1c8cbc Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 8 Sep 2021 11:04:03 +0200 Subject: [PATCH 11/14] fix #5411: disallow forsystemvms if ip range is dedicated --- .../ConfigurationManagerImpl.java | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index 5886c96da749..4fe0f4e9a867 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -4285,8 +4285,21 @@ public Vlan updateVlanAndPublicIpRange(final long id, String startIp, } } - if (forSystemVms != null && VlanType.DirectAttached.equals(vlanRange.getVlanType())) { - throw new InvalidParameterValueException("forSystemVms is not available for this IP range with vlan type: " + VlanType.DirectAttached); + 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 maps = _accountVlanMapDao.listAccountVlanMapsByVlan(id); + if (maps != null && !maps.isEmpty()) { + throw new InvalidParameterValueException("Specified Public IP range has already been dedicated to an account"); + } + + List 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())) { @@ -4346,7 +4359,7 @@ public Vlan updateVlanAndPublicIpRange(final long id, String startIp, s_logger.debug("lock vlan " + id + " is acquired"); } - commitUpdateVlanAndIpRange(id, newStartIP, newEndIP, currentStartIP, currentEndIP, true, forSystemVms); + 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); @@ -4391,7 +4404,7 @@ public Vlan updateVlanAndPublicIpRange(final long id, String startIp, s_logger.debug("lock vlan " + id + " is acquired"); } - commitUpdateVlanAndIpRange(id, startIpv6, endIpv6, currentStartIPv6, currentEndIPv6, false, null); + 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); @@ -4405,7 +4418,8 @@ public Vlan updateVlanAndPublicIpRange(final long id, String startIp, 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 forSystemvms) { + 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() { @Override @@ -4415,7 +4429,6 @@ public VlanVO doInTransaction(final TransactionStatus status) { if (ipv4) { vlanRange.setIpRange(newStartIP + "-" + newEndIP); _vlanDao.update(vlanRange.getId(), vlanRange); - final Boolean isRangeForSystemVM = checkIfVlanRangeIsForSystemVM(id); 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."); } From 34174245892ef9d9735ff83e9fde582f5a9ffac3 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 8 Sep 2021 11:04:16 +0200 Subject: [PATCH 12/14] update #5411: ui changes --- ui/public/locales/en.json | 2 + .../views/infra/network/IpRangesTabPublic.vue | 90 +++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 90fcad857c15..f8f01e572a05 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -2237,6 +2237,7 @@ "label.unmanaged.instances": "Unmanaged Instances", "label.untagged": "Untagged", "label.update.instance.group": "Update Instance Group", +"label.update.ip.range": "Update IP range", "label.update.physical.network": "Update Physical Network", "label.update.project.resources": "Update project resources", "label.update.project.role": "Update project role", @@ -3279,6 +3280,7 @@ "message.success.scale.kubernetes": "Successfully scaled Kubernetes cluster", "message.success.unmanage.instance": "Successfully unmanaged instance", "message.success.update.ipaddress": "Successfully updated IP Address", +"message.success.update.iprange": "Successfully updated IP range", "message.success.update.kubeversion": "Successfully updated Kubernetes supported version", "message.success.update.user": "Successfully updated user", "message.success.upgrade.kubernetes": "Successfully upgraded Kubernetes cluster", diff --git a/ui/src/views/infra/network/IpRangesTabPublic.vue b/ui/src/views/infra/network/IpRangesTabPublic.vue index 7e66d691b361..7546b9df47c4 100644 --- a/ui/src/views/infra/network/IpRangesTabPublic.vue +++ b/ui/src/views/infra/network/IpRangesTabPublic.vue @@ -54,6 +54,13 @@ type="danger" @click="() => handleRemoveAccount(record.id)" :disabled="!('releasePublicIpRange' in $store.getters.apis)" /> + + + + + + + + + + + + + + + + + + + + + + + +
+ {{ $t('label.cancel') }} + {{ $t('label.ok') }} +
+
+
+ @@ -264,6 +317,7 @@ export default { domains: [], domainsLoading: false, addIpRangeModal: false, + updateIpRangeModal: false, showAccountFields: false, podsLoading: false, pods: [], @@ -427,6 +481,10 @@ export default { handleOpenAddIpRangeModal () { this.addIpRangeModal = true }, + handleUpdateIpRangeModal (item) { + this.selectedItem = item + this.updateIpRangeModal = true + }, handleDeleteIpRange (id) { this.componentLoading = true api('deleteVlanIpRange', { id }).then(() => { @@ -482,6 +540,38 @@ export default { }) }) }, + handleUpdateIpRange (e) { + if (this.componentLoading) return + this.form.validateFields((error, values) => { + if (error) return + + this.componentLoading = true + this.updateIpRangeModal = false + var params = { + id: this.selectedItem.id, + gateway: values.gateway, + netmask: values.netmask, + startip: values.startip, + endip: values.endip, + forsystemvms: values.forsystemvms + } + api('updateVlanIpRange', params).then(() => { + this.$notification.success({ + message: this.$t('message.success.update.iprange') + }) + }).catch(error => { + this.$notification.error({ + message: `${this.$t('label.error')} ${error.response.status}`, + description: error.response.data.updatevlaniprangeresponse + ? error.response.data.updatevlaniprangeresponse.errortext : error.response.data.errorresponse.errortext, + duration: 0 + }) + }).finally(() => { + this.componentLoading = false + this.fetchData() + }) + }) + }, changePage (page, pageSize) { this.page = page this.pageSize = pageSize From 97a98e1c1534cccd7f15fd4cd0954d4591b9c8f8 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Fri, 17 Sep 2021 09:31:57 +0200 Subject: [PATCH 13/14] update #5411: support gateway/netmask change --- .../configuration/ConfigurationService.java | 4 - .../src/main/java/com/cloud/dc/VlanVO.java | 8 + .../com/cloud/network/dao/IPAddressDao.java | 3 + .../cloud/network/dao/IPAddressDaoImpl.java | 9 + .../cloud/network/dao/UserIpv6AddressDao.java | 3 + .../network/dao/UserIpv6AddressDaoImpl.java | 10 + .../ConfigurationManagerImpl.java | 238 +++++++++--------- 7 files changed, 146 insertions(+), 129 deletions(-) diff --git a/api/src/main/java/com/cloud/configuration/ConfigurationService.java b/api/src/main/java/com/cloud/configuration/ConfigurationService.java index ee41fa7c2b84..6a51f7e1547c 100644 --- a/api/src/main/java/com/cloud/configuration/ConfigurationService.java +++ b/api/src/main/java/com/cloud/configuration/ConfigurationService.java @@ -275,11 +275,7 @@ Vlan createVlanAndPublicIpRange(CreateVlanIpRangeCmd cmd) throws InsufficientCap /** * Updates the IP address Range for the VLAN on the database - * @param cmd * @return The Updated Vlan Object - * @throws ConcurrentOperationException - * @throws ResourceUnavailableException - * @throws ResourceAllocationException */ Vlan updateVlanAndPublicIpRange(UpdateVlanIpRangeCmd cmd) throws ConcurrentOperationException, ResourceUnavailableException, ResourceAllocationException; diff --git a/engine/schema/src/main/java/com/cloud/dc/VlanVO.java b/engine/schema/src/main/java/com/cloud/dc/VlanVO.java index 91d2bdb6129e..20b07e983b86 100644 --- a/engine/schema/src/main/java/com/cloud/dc/VlanVO.java +++ b/engine/schema/src/main/java/com/cloud/dc/VlanVO.java @@ -118,11 +118,19 @@ public String getVlanGateway() { return vlanGateway; } + public void setVlanGateway(String vlanGateway) { + this.vlanGateway = vlanGateway; + } + @Override public String getVlanNetmask() { return vlanNetmask; } + public void setVlanNetmask(String vlanNetmask) { + this.vlanNetmask = vlanNetmask; + } + @Override public long getDataCenterId() { return dataCenterId; diff --git a/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDao.java b/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDao.java index 24d77db711aa..8ee23008d71b 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDao.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDao.java @@ -19,6 +19,7 @@ import java.util.List; import com.cloud.dc.Vlan.VlanType; +import com.cloud.network.IpAddress.State; import com.cloud.utils.db.GenericDao; import com.cloud.utils.net.Ip; @@ -32,6 +33,8 @@ public interface IPAddressDao extends GenericDao { List listByVlanId(long vlanId); + List listByVlanIdAndState(long vlanId, State state); + List listByDcIdIpAddress(long dcId, String ipAddress); List listByDcId(long dcId); diff --git a/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDaoImpl.java index 43345b916fed..589f10a15f3e 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDaoImpl.java @@ -78,6 +78,7 @@ public void init() { AllFieldsSearch.and("dataCenterId", AllFieldsSearch.entity().getDataCenterId(), Op.EQ); AllFieldsSearch.and("ipAddress", AllFieldsSearch.entity().getAddress(), Op.EQ); AllFieldsSearch.and("vlan", AllFieldsSearch.entity().getVlanId(), Op.EQ); + AllFieldsSearch.and("state", AllFieldsSearch.entity().getState(), Op.EQ); AllFieldsSearch.and("accountId", AllFieldsSearch.entity().getAllocatedToAccountId(), Op.EQ); AllFieldsSearch.and("sourceNat", AllFieldsSearch.entity().isSourceNat(), Op.EQ); AllFieldsSearch.and("network", AllFieldsSearch.entity().getAssociatedWithNetworkId(), Op.EQ); @@ -471,4 +472,12 @@ public void lockRange(long vlandbId) { sc.setParameters("vlan", vlandbId); lockRows(sc, null, true); } + + @Override + public List listByVlanIdAndState(long vlanId, State state) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("vlan", vlanId); + sc.setParameters("state", state); + return listBy(sc); + } } diff --git a/engine/schema/src/main/java/com/cloud/network/dao/UserIpv6AddressDao.java b/engine/schema/src/main/java/com/cloud/network/dao/UserIpv6AddressDao.java index 80c39d283a4d..aee1cf2a01ed 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/UserIpv6AddressDao.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/UserIpv6AddressDao.java @@ -18,6 +18,7 @@ import java.util.List; +import com.cloud.network.IpAddress; import com.cloud.network.UserIpv6AddressVO; import com.cloud.utils.db.GenericDao; @@ -26,6 +27,8 @@ public interface UserIpv6AddressDao extends GenericDao List listByVlanId(long vlanId); + List listByVlanIdAndState(long vlanId, IpAddress.State state); + List listByDcId(long dcId); List listByNetwork(long networkId); diff --git a/engine/schema/src/main/java/com/cloud/network/dao/UserIpv6AddressDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/UserIpv6AddressDaoImpl.java index 9a7737fe12cd..08f0829f4acc 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/UserIpv6AddressDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/UserIpv6AddressDaoImpl.java @@ -19,6 +19,7 @@ import java.util.List; +import com.cloud.network.IpAddress; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -43,6 +44,7 @@ public UserIpv6AddressDaoImpl() { AllFieldsSearch.and("dataCenterId", AllFieldsSearch.entity().getDataCenterId(), Op.EQ); AllFieldsSearch.and("ipAddress", AllFieldsSearch.entity().getAddress(), Op.EQ); AllFieldsSearch.and("vlan", AllFieldsSearch.entity().getVlanId(), Op.EQ); + AllFieldsSearch.and("state", AllFieldsSearch.entity().getState(), Op.EQ); AllFieldsSearch.and("accountId", AllFieldsSearch.entity().getAccountId(), Op.EQ); AllFieldsSearch.and("network", AllFieldsSearch.entity().getNetworkId(), Op.EQ); AllFieldsSearch.and("physicalNetworkId", AllFieldsSearch.entity().getPhysicalNetworkId(), Op.EQ); @@ -69,6 +71,14 @@ public List listByVlanId(long vlanId) { return listBy(sc); } + @Override + public List listByVlanIdAndState(long vlanId, IpAddress.State state) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("vlan", vlanId); + sc.setParameters("state", state); + return listBy(sc); + } + @Override public List listByDcId(long dcId) { SearchCriteria sc = AllFieldsSearch.create(); diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index 4fe0f4e9a867..39fe82e14b9d 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -183,7 +183,6 @@ import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.TrafficType; import com.cloud.network.PhysicalNetwork; -import com.cloud.network.UserIpv6Address; import com.cloud.network.UserIpv6AddressVO; import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.IPAddressDao; @@ -4302,54 +4301,109 @@ public Vlan updateVlanAndPublicIpRange(final long id, String startIp, } } 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()); - } + updateVlanAndIpv4Range(id, vlanRange, startIp, endIp, gateway, netmask, isRangeForSystemVM, forSystemVms); + } + if (ipv6) { + updateVlanAndIpv6Range(id, vlanRange, startIpv6, endIpv6, ip6Gateway, ip6Cidr, isRangeForSystemVM, forSystemVms); + } + return _vlanDao.findById(id); + } - if (gateway == null) { - gateway = vlanRange.getVlanGateway(); - } + private void updateVlanAndIpv4Range(final long id, final VlanVO vlanRange, + String startIp, + String endIp, + String gateway, + String netmask, + final Boolean isRangeForSystemVM, + final Boolean forSystemVms) { + final List listAllocatedIPs = _publicIpAddressDao.listByVlanIdAndState(id, IpAddress.State.Allocated); - if (netmask == null) { - netmask = vlanRange.getVlanNetmask(); - } + if (gateway != null && !gateway.equals(vlanRange.getVlanGateway()) && CollectionUtils.isNotEmpty(listAllocatedIPs)) { + throw new InvalidParameterValueException(String.format("Unable to change gateway to %s because some IPs are in use", gateway)); + } + if (netmask != null && !netmask.equals(vlanRange.getVlanNetmask()) && CollectionUtils.isNotEmpty(listAllocatedIPs)) { + throw new InvalidParameterValueException(String.format("Unable to change netmask to %s because some IPs are in use", netmask)); + } - final String[] existingVlanIPRangeArray = vlanRange.getIpRange().split("-"); - final String currentStartIP = existingVlanIPRangeArray[0]; - final String currentEndIP = existingVlanIPRangeArray[1]; + gateway = MoreObjects.firstNonNull(gateway, vlanRange.getVlanGateway()); + netmask = MoreObjects.firstNonNull(netmask, vlanRange.getVlanNetmask()); - if (startIp == null) { - startIp = currentStartIP; - } + final String[] existingVlanIPRangeArray = vlanRange.getIpRange().split("-"); + final String currentStartIP = existingVlanIPRangeArray[0]; + final String currentEndIP = existingVlanIPRangeArray[1]; - if (endIp == null) { - endIp = currentEndIP; - } + startIp = MoreObjects.firstNonNull(startIp, currentStartIP); + endIp = MoreObjects.firstNonNull(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 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); + + checkAllocatedIpsAreWithinVlanRange(listAllocatedIPs, 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); } - 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); + if (s_logger.isDebugEnabled()) { + s_logger.debug("lock vlan " + id + " is acquired"); } - checkGatewayOverlap(startIp, endIp, gateway); + commitUpdateVlanAndIpRange(id, newStartIP, newEndIP, currentStartIP, currentEndIP, gateway, netmask,true, isRangeForSystemVM, forSystemVms); - final List ips = _publicIpAddressDao.listByVlanId(id); - checkAllocatedIpsAreWithinVlanRange(ips, startIp, endIp, 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); + } + } - try { - final String newStartIP = startIp; - final String newEndIP = endIp; + private void updateVlanAndIpv6Range(final long id, final VlanVO vlanRange, + String startIpv6, + String endIpv6, + String ip6Gateway, + String ip6Cidr, + final Boolean isRangeForSystemVM, + final Boolean forSystemVms) { + final List listAllocatedIPs = _ipv6Dao.listByVlanIdAndState(id, IpAddress.State.Allocated); + if (ip6Gateway != null && !ip6Gateway.equals(vlanRange.getIp6Gateway()) && CollectionUtils.isNotEmpty(listAllocatedIPs)) { + throw new InvalidParameterValueException(String.format("Unable to change ipv6 gateway to %s because some IPs are in use", ip6Gateway)); + } + if (ip6Cidr != null && !ip6Cidr.equals(vlanRange.getIp6Cidr()) && CollectionUtils.isNotEmpty(listAllocatedIPs)) { + throw new InvalidParameterValueException(String.format("Unable to change ipv6 cidr to %s because some IPs are in use", ip6Cidr)); + } + 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]; + + startIpv6 = MoreObjects.firstNonNull(startIpv6, currentStartIPv6); + endIpv6 = MoreObjects.firstNonNull(endIpv6, currentEndIPv6); + + if (startIpv6 != currentStartIPv6 || endIpv6 != currentEndIPv6) { + _networkModel.checkIp6Parameters(startIpv6, endIpv6, ip6Gateway, ip6Cidr); + checkAllocatedIpv6sAreWithinVlanRange(listAllocatedIPs, startIpv6, endIpv6); + + try { VlanVO range = _vlanDao.acquireInLockTable(id, 30); if (range == null) { throw new CloudRuntimeException("Unable to acquire vlan configuration: " + id); @@ -4359,7 +4413,7 @@ public Vlan updateVlanAndPublicIpRange(final long id, String startIp, s_logger.debug("lock vlan " + id + " is acquired"); } - commitUpdateVlanAndIpRange(id, newStartIP, newEndIP, currentStartIP, currentEndIP, true, isRangeForSystemVM, forSystemVms); + commitUpdateVlanAndIpRange(id, startIpv6, endIpv6, currentStartIPv6, currentEndIPv6, ip6Gateway, ip6Cidr, false, isRangeForSystemVM,forSystemVms); } catch (final Exception e) { s_logger.error("Unable to edit VlanRange due to " + e.getMessage(), e); @@ -4368,57 +4422,10 @@ public Vlan updateVlanAndPublicIpRange(final long id, String startIp, _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 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 String gateway, final String netmask, final boolean ipv4, final Boolean isRangeForSystemVM, final Boolean forSystemvms) { return Transaction.execute(new TransactionCallback() { @@ -4428,12 +4435,16 @@ public VlanVO doInTransaction(final TransactionStatus status) { s_logger.debug("Updating vlan range " + vlanRange.getId()); if (ipv4) { vlanRange.setIpRange(newStartIP + "-" + newEndIP); + vlanRange.setVlanGateway(gateway); + vlanRange.setVlanNetmask(netmask); _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); + vlanRange.setIp6Gateway(gateway); + vlanRange.setIp6Cidr(netmask); _vlanDao.update(vlanRange.getId(), vlanRange); } return vlanRange; @@ -4452,27 +4463,16 @@ private boolean checkIfVlanRangeIsForSystemVM(final long vlanId) { return initialIsSystemVmValue; } - private void checkAllocatedIpsAreWithinVlanRange(List ips, String startIp, String endIp, Boolean forSystemVms) { - - List listAllocatedIPs = new ArrayList<>(); - for (final IPAddressVO ip : ips) { - if (ip.getState() == IpAddress.State.Allocated) { - listAllocatedIPs.add(ip); - } - } + private void checkAllocatedIpsAreWithinVlanRange + (List listAllocatedIPs, String startIp, String endIp, Boolean forSystemVms) { 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 ((!Strings.isNullOrEmpty(startIp) && NetUtils.ip2Long(startIp) > NetUtils.ip2Long(allocatedIP.getAddress().addr())) + || (!Strings.isNullOrEmpty(endIp) && NetUtils.ip2Long(endIp) < NetUtils.ip2Long(allocatedIP.getAddress().addr()))) { + throw new InvalidParameterValueException(String.format("The start IP address must be less than or equal to %s which is already in use. " + + "The end IP address must be greater than or equal to %s which is already in use. " + + "There are %d IPs already allocated in this range.", + listAllocatedIPs.get(0).getAddress(), listAllocatedIPs.get(listAllocatedIPs.size() - 1).getAddress(), 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())); @@ -4480,29 +4480,17 @@ private void checkAllocatedIpsAreWithinVlanRange(List ips, String s } } - private void checkAllocatedIpv6sAreWithinVlanRange(List ips, String startIpv6, String endIpv6) { - - List listAllocatedIPs = new ArrayList<>(); - for (final UserIpv6AddressVO ip : ips) { - if (ip.getState() == UserIpv6Address.State.Allocated) { - listAllocatedIPs.add(ip); - } - } + private void checkAllocatedIpv6sAreWithinVlanRange(List listAllocatedIPs, String startIpv6, String endIpv6) { 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()); + if ((!Strings.isNullOrEmpty(startIpv6) + && IPv6Address.fromString(startIpv6).toBigInteger().compareTo(IPv6Address.fromString(allocatedIP.getAddress()).toBigInteger()) > 0) + || (!Strings.isNullOrEmpty(endIpv6) + && IPv6Address.fromString(endIpv6).toBigInteger().compareTo(IPv6Address.fromString(allocatedIP.getAddress()).toBigInteger()) < 0)) { + throw new InvalidParameterValueException(String.format("The start IPv6 address must be less than or equal to %s which is already in use. " + + "The end IPv6 address must be greater than or equal to %s which is already in use. " + + "There are %d IPv6 addresses already allocated in this range.", + listAllocatedIPs.get(0).getAddress(), listAllocatedIPs.get(listAllocatedIPs.size() - 1).getAddress(), listAllocatedIPs.size())); } } } From e7efaa8d7cee3c7be8117c7391a5c16917f48842 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Fri, 17 Sep 2021 12:08:24 +0200 Subject: [PATCH 14/14] update #5411: change to sync call and fix bugs --- .../command/admin/vlan/UpdateVlanIpRangeCmd.java | 16 +--------------- .../configuration/ConfigurationManagerImpl.java | 7 ++----- 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmd.java index 8d07f579ba91..7a7775e48630 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/UpdateVlanIpRangeCmd.java @@ -20,7 +20,6 @@ import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; -import org.apache.cloudstack.api.BaseAsyncCmd; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; @@ -28,7 +27,6 @@ import org.apache.log4j.Logger; import com.cloud.dc.Vlan; -import com.cloud.event.EventTypes; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; @@ -39,7 +37,7 @@ VlanIpRangeResponse.class, since = "4.16.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = {RoleType.Admin}) -public class UpdateVlanIpRangeCmd extends BaseAsyncCmd { +public class UpdateVlanIpRangeCmd extends BaseCmd { public static final String APINAME = "updateVlanIpRange"; public static final Logger s_logger = Logger.getLogger(UpdateVlanIpRangeCmd.class.getName()); @@ -140,18 +138,6 @@ public Boolean isForSystemVms() { /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// - @Override - public String getEventType() { - return EventTypes.EVENT_VLAN_IP_RANGE_UPDATE; - } - - @Override - public String getEventDescription() { - return "Update vlan ip range " + getId() + " [StartIp=" + getStartIp() + ", EndIp=" + getEndIp() + ", gateway=" + getGateway() + ", netmask=" + getNetmask() - + ", StartIpv6=" + getStartIpv6() + ", EndIpv6=" + getEndIpv6() + ", ip6gateway=" + getIp6Gateway() + ", ip6cidr=" + getIp6Cidr() + ']'; - } - - @Override public void execute() throws ResourceUnavailableException, ResourceAllocationException { try { diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index 39fe82e14b9d..9dd1d5ea5c70 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -4342,10 +4342,7 @@ private void updateVlanAndIpv4Range(final long id, final VlanVO vlanRange, 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); - } + checkIpRange(startIp, endIp, cidrAddress, cidrSize); checkGatewayOverlap(startIp, endIp, gateway); @@ -4832,7 +4829,7 @@ public List doInTransaction(final TransactionStatus status) { } }); - return problemIps != null && problemIps.size() == 0; + return CollectionUtils.isEmpty(problemIps); } @DB