diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index 437ff05d28d0..6c9229bc6ec2 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -855,7 +855,7 @@ public VlanIpRangeResponse createVlanIpRangeResponse(Class ips = _publicIpAddressDao.listByVlanId(vlanDbId); for (final IPAddressVO ip : ips) { - forSystemVms = ip.isForSystemVms(); + if (ip.isForSystemVms()) { + throw new InvalidParameterValueException(ip.getAddress() + " Public IP address in range is dedicated to system vms "); + } final Long allocatedToAccountId = ip.getAllocatedToAccountId(); if (allocatedToAccountId != null) { if (vlanOwner != null && allocatedToAccountId != vlanOwner.getId()) { @@ -5346,7 +5347,7 @@ public Vlan dedicatePublicIpRange(final DedicatePublicIpRangeCmd cmd) throws Res UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_ASSIGN, vlanOwner.getId(), ip.getDataCenterId(), ip.getId(), ip.getAddress().toString(), ip.isSourceNat(), vlan.getVlanType().toString(), ip.getSystem(), usageHidden, ip.getClass().getName(), ip.getUuid()); } - } else if (domain != null && !forSystemVms) { + } else if (domain != null) { // Create an DomainVlanMapVO entry DomainVlanMapVO domainVlanMapVO = new DomainVlanMapVO(domain.getId(), vlan.getId()); _domainVlanMapDao.persist(domainVlanMapVO); @@ -7164,7 +7165,6 @@ public Account getVlanAccount(final long vlanId) { @Override public Domain getVlanDomain(long vlanId) { Vlan vlan = _vlanDao.findById(vlanId); - Long domainId = null; // if vlan is Virtual Domain specific, get vlan information from the // accountVlanMap; otherwise get account information diff --git a/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java b/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java index f6df85f23085..4b7cabc61e3c 100644 --- a/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java +++ b/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java @@ -330,19 +330,10 @@ private List getIpv6SupportingVlanRangeIds(long dcId) throws InsufficientA @DB private IPAddressVO assignAndAllocateIpAddressEntry(final Account owner, final VlanType vlanUse, final Long guestNetworkId, final boolean sourceNat, final boolean allocate, final boolean isSystem, - final Long vpcId, final Boolean displayIp, final boolean fetchFromDedicatedRange, + final Long vpcId, final Boolean displayIp, final List addressVOS) throws CloudRuntimeException { return Transaction.execute((TransactionCallbackWithException) status -> { IPAddressVO finalAddress = null; - if (!fetchFromDedicatedRange && VlanType.VirtualNetwork.equals(vlanUse)) { - // Check that the maximum number of public IPs for the given accountId will not be exceeded - try { - _resourceLimitMgr.checkResourceLimit(owner, ResourceType.public_ip); - } catch (ResourceAllocationException ex) { - s_logger.warn("Failed to allocate resource of type " + ex.getResourceType() + " for account " + owner); - throw new AccountLimitException("Maximum number of public IP addresses for account: " + owner.getAccountName() + " has been exceeded."); - } - } for (IPAddressVO possibleAddr : addressVOS) { if (possibleAddr.getState() != State.Free) { @@ -492,9 +483,8 @@ public boolean configure(String name, Map params) { AssignIpAddressSearch.and("dc", AssignIpAddressSearch.entity().getDataCenterId(), Op.EQ); AssignIpAddressSearch.and("allocated", AssignIpAddressSearch.entity().getAllocatedTime(), Op.NULL); AssignIpAddressSearch.and("vlanId", AssignIpAddressSearch.entity().getVlanId(), Op.IN); - if (SystemVmPublicIpReservationModeStrictness.value()) { - AssignIpAddressSearch.and("forSystemVms", AssignIpAddressSearch.entity().isForSystemVms(), Op.EQ); - } + AssignIpAddressSearch.and("forSystemVms", AssignIpAddressSearch.entity().isForSystemVms(), Op.EQ); + SearchBuilder vlanSearch = _vlanDao.createSearchBuilder(); vlanSearch.and("type", vlanSearch.entity().getVlanType(), Op.EQ); vlanSearch.and("networkId", vlanSearch.entity().getNetworkId(), Op.EQ); @@ -810,6 +800,10 @@ public PublicIp fetchNewPublicIp(final long dcId, final Long podId, final List addrs = listAvailablePublicIps(dcId, podId, vlanDbIds, owner, vlanUse, guestNetworkId, sourceNat, assign, allocate, requestedIp, requestedGateway, isSystem, vpcId, displayIp, forSystemVms, true); IPAddressVO addr = addrs.get(0); + if (assign) { + addr = assignAndAllocateIpAddressEntry(owner, vlanUse, guestNetworkId, sourceNat, allocate, + isSystem,vpcId, displayIp, addrs); + } if (vlanUse == VlanType.VirtualNetwork) { _firewallMgr.addSystemFirewallRules(addr, owner); } @@ -821,128 +815,99 @@ public PublicIp fetchNewPublicIp(final long dcId, final Long podId, final List listAvailablePublicIps(final long dcId, final Long podId, final List vlanDbIds, final Account owner, final VlanType vlanUse, final Long guestNetworkId, final boolean sourceNat, final boolean assign, final boolean allocate, final String requestedIp, final String requestedGateway, final boolean isSystem, final Long vpcId, final Boolean displayIp, final boolean forSystemVms, final boolean lockOneRow) throws InsufficientAddressCapacityException { - return Transaction.execute(new TransactionCallbackWithException, InsufficientAddressCapacityException>() { - @Override - public List doInTransaction(TransactionStatus status) throws InsufficientAddressCapacityException { - StringBuilder errorMessage = new StringBuilder("Unable to get ip address in "); - boolean fetchFromDedicatedRange = false; - List dedicatedVlanDbIds = new ArrayList(); - List nonDedicatedVlanDbIds = new ArrayList(); - DataCenter zone = _entityMgr.findById(DataCenter.class, dcId); - - SearchCriteria sc = null; - if (podId != null) { - sc = AssignIpAddressFromPodVlanSearch.create(); - sc.setJoinParameters("podVlanMapSB", "podId", podId); - errorMessage.append(" pod id=" + podId); - } else { - sc = AssignIpAddressSearch.create(); - errorMessage.append(" zone id=" + dcId); - } - - // If owner has dedicated Public IP ranges, fetch IP from the dedicated range - // Otherwise fetch IP from the system pool - Network network = _networksDao.findById(guestNetworkId); - //Checking if network is null in the case of system VM's. At the time of allocation of IP address to systemVm, no network is present. - if(network == null || !(network.getGuestType() == GuestType.Shared && zone.getNetworkType() == NetworkType.Advanced)) { - List maps = _accountVlanMapDao.listAccountVlanMapsByAccount(owner.getId()); - for (AccountVlanMapVO map : maps) { - if (vlanDbIds == null || vlanDbIds.contains(map.getVlanDbId())) - dedicatedVlanDbIds.add(map.getVlanDbId()); - } - } - List domainMaps = _domainVlanMapDao.listDomainVlanMapsByDomain(owner.getDomainId()); - for (DomainVlanMapVO map : domainMaps) { - if (vlanDbIds == null || vlanDbIds.contains(map.getVlanDbId())) - dedicatedVlanDbIds.add(map.getVlanDbId()); - } - List nonDedicatedVlans = _vlanDao.listZoneWideNonDedicatedVlans(dcId); - for (VlanVO nonDedicatedVlan : nonDedicatedVlans) { - if (vlanDbIds == null || vlanDbIds.contains(nonDedicatedVlan.getId())) - nonDedicatedVlanDbIds.add(nonDedicatedVlan.getId()); - } - if (vlanUse == VlanType.VirtualNetwork) { - if (!dedicatedVlanDbIds.isEmpty()) { - fetchFromDedicatedRange = true; - sc.setParameters("vlanId", dedicatedVlanDbIds.toArray()); - errorMessage.append(", vlanId id=" + Arrays.toString(dedicatedVlanDbIds.toArray())); - } else if (!nonDedicatedVlanDbIds.isEmpty()) { - sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray()); - errorMessage.append(", vlanId id=" + Arrays.toString(nonDedicatedVlanDbIds.toArray())); - } else { - if (podId != null) { - InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", Pod.class, podId); - ex.addProxyObject(ApiDBUtils.findPodById(podId).getUuid()); - throw ex; - } - s_logger.warn(errorMessage.toString()); - InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", DataCenter.class, dcId); - ex.addProxyObject(ApiDBUtils.findZoneById(dcId).getUuid()); - throw ex; - } - } + StringBuilder errorMessage = new StringBuilder("Unable to get ip address in "); + boolean fetchFromDedicatedRange = false; + List dedicatedVlanDbIds = new ArrayList(); + List nonDedicatedVlanDbIds = new ArrayList(); + DataCenter zone = _entityMgr.findById(DataCenter.class, dcId); + + SearchCriteria sc = null; + if (podId != null) { + sc = AssignIpAddressFromPodVlanSearch.create(); + sc.setJoinParameters("podVlanMapSB", "podId", podId); + errorMessage.append(" pod id=" + podId); + } else { + sc = AssignIpAddressSearch.create(); + errorMessage.append(" zone id=" + dcId); + } - sc.setParameters("dc", dcId); + sc.setParameters("dc", dcId); - // for direct network take ip addresses only from the vlans belonging to the network - if (vlanUse == VlanType.DirectAttached) { - sc.setJoinParameters("vlan", "networkId", guestNetworkId); - errorMessage.append(", network id=" + guestNetworkId); - } - if (requestedGateway != null) { - sc.setJoinParameters("vlan", "vlanGateway", requestedGateway); - errorMessage.append(", requested gateway=" + requestedGateway); - } - sc.setJoinParameters("vlan", "type", vlanUse); - String routerIpAddress = null; - if (network != null) { - NetworkDetailVO routerIpDetail = _networkDetailsDao.findDetail(network.getId(), ApiConstants.ROUTER_IP); - routerIpAddress = routerIpDetail != null ? routerIpDetail.getValue() : null; - } - if (requestedIp != null) { - sc.addAnd("address", SearchCriteria.Op.EQ, requestedIp); - errorMessage.append(": requested ip " + requestedIp + " is not available"); - } else if (routerIpAddress != null) { - sc.addAnd("address", Op.NEQ, routerIpAddress); - } + // for direct network take ip addresses only from the vlans belonging to the network + if (vlanUse == VlanType.DirectAttached) { + sc.setJoinParameters("vlan", "networkId", guestNetworkId); + errorMessage.append(", network id=" + guestNetworkId); + } + if (requestedGateway != null) { + sc.setJoinParameters("vlan", "vlanGateway", requestedGateway); + errorMessage.append(", requested gateway=" + requestedGateway); + } + sc.setJoinParameters("vlan", "type", vlanUse); - boolean ascOrder = ! forSystemVms; - Filter filter = new Filter(IPAddressVO.class, "forSystemVms", ascOrder, 0l, 1l); - if (SystemVmPublicIpReservationModeStrictness.value()) { - sc.setParameters("forSystemVms", forSystemVms); - } + Network network = _networksDao.findById(guestNetworkId); + String routerIpAddress = null; + if (network != null) { + NetworkDetailVO routerIpDetail = _networkDetailsDao.findDetail(network.getId(), ApiConstants.ROUTER_IP); + routerIpAddress = routerIpDetail != null ? routerIpDetail.getValue() : null; + } + if (requestedIp != null) { + sc.addAnd("address", SearchCriteria.Op.EQ, requestedIp); + errorMessage.append(": requested ip " + requestedIp + " is not available"); + } else if (routerIpAddress != null) { + sc.addAnd("address", Op.NEQ, routerIpAddress); + } - filter.addOrderBy(IPAddressVO.class,"vlanId", true); + boolean ascOrder = ! forSystemVms; + Filter filter = new Filter(IPAddressVO.class, "forSystemVms", ascOrder, 0l, 1l); - List addrs; + filter.addOrderBy(IPAddressVO.class,"vlanId", true); - if (lockOneRow) { - addrs = _ipAddressDao.lockRows(sc, filter, true); - } else { - addrs = new ArrayList<>(_ipAddressDao.search(sc, null)); - } + List addrs = new ArrayList<>(); - // If all the dedicated IPs of the owner are in use fetch an IP from the system pool - if ((!lockOneRow || (lockOneRow && addrs.size() == 0)) && fetchFromDedicatedRange && vlanUse == VlanType.VirtualNetwork) { - // Verify if account is allowed to acquire IPs from the system - boolean useSystemIps = UseSystemPublicIps.valueIn(owner.getId()); - if (useSystemIps && !nonDedicatedVlanDbIds.isEmpty()) { - fetchFromDedicatedRange = false; - sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray()); - errorMessage.append(", vlanId id=" + Arrays.toString(nonDedicatedVlanDbIds.toArray())); - if (lockOneRow) { - addrs = _ipAddressDao.lockRows(sc, filter, true); - } else { - addrs.addAll(_ipAddressDao.search(sc, null)); - } - } + if (forSystemVms) { + // Get Public IPs for system vms in dedicated ranges + sc.setParameters("forSystemVms", true); + if (lockOneRow) { + addrs = _ipAddressDao.lockRows(sc, filter, true); + } else { + addrs = new ArrayList<>(_ipAddressDao.search(sc, null)); + } + } + if ((!lockOneRow || (lockOneRow && CollectionUtils.isEmpty(addrs))) && + !(forSystemVms && SystemVmPublicIpReservationModeStrictness.value())) { + sc.setParameters("forSystemVms", false); + // If owner has dedicated Public IP ranges, fetch IP from the dedicated range + // Otherwise fetch IP from the system pool + // Checking if network is null in the case of system VM's. At the time of allocation of IP address to systemVm, no network is present. + if (network == null || !(network.getGuestType() == GuestType.Shared && zone.getNetworkType() == NetworkType.Advanced)) { + List maps = _accountVlanMapDao.listAccountVlanMapsByAccount(owner.getId()); + for (AccountVlanMapVO map : maps) { + if (vlanDbIds == null || vlanDbIds.contains(map.getVlanDbId())) + dedicatedVlanDbIds.add(map.getVlanDbId()); } - - if (lockOneRow && addrs.size() == 0) { + } + List domainMaps = _domainVlanMapDao.listDomainVlanMapsByDomain(owner.getDomainId()); + for (DomainVlanMapVO map : domainMaps) { + if (vlanDbIds == null || vlanDbIds.contains(map.getVlanDbId())) + dedicatedVlanDbIds.add(map.getVlanDbId()); + } + List nonDedicatedVlans = _vlanDao.listZoneWideNonDedicatedVlans(dcId); + for (VlanVO nonDedicatedVlan : nonDedicatedVlans) { + if (vlanDbIds == null || vlanDbIds.contains(nonDedicatedVlan.getId())) + nonDedicatedVlanDbIds.add(nonDedicatedVlan.getId()); + } + if (vlanUse == VlanType.VirtualNetwork) { + if (!dedicatedVlanDbIds.isEmpty()) { + fetchFromDedicatedRange = true; + sc.setParameters("vlanId", dedicatedVlanDbIds.toArray()); + errorMessage.append(", vlanId id=" + Arrays.toString(dedicatedVlanDbIds.toArray())); + } else if (!nonDedicatedVlanDbIds.isEmpty()) { + sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray()); + errorMessage.append(", vlanId id=" + Arrays.toString(nonDedicatedVlanDbIds.toArray())); + } else { if (podId != null) { InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", Pod.class, podId); - // for now, we hardcode the table names, but we should ideally do a lookup for the tablename from the VO object. ex.addProxyObject(ApiDBUtils.findPodById(podId).getUuid()); throw ex; } @@ -951,17 +916,58 @@ public List doInTransaction(TransactionStatus status) throws Insuff ex.addProxyObject(ApiDBUtils.findZoneById(dcId).getUuid()); throw ex; } + } + if (lockOneRow) { + addrs = _ipAddressDao.lockRows(sc, filter, true); + } else { + addrs = new ArrayList<>(_ipAddressDao.search(sc, null)); + } - if (lockOneRow) { - assert (addrs.size() == 1) : "Return size is incorrect: " + addrs.size(); - } - if (assign) { - assignAndAllocateIpAddressEntry(owner, vlanUse, guestNetworkId, sourceNat, allocate, - isSystem,vpcId, displayIp, fetchFromDedicatedRange, addrs); + // If all the dedicated IPs of the owner are in use fetch an IP from the system pool + if ((!lockOneRow || (lockOneRow && addrs.size() == 0)) && fetchFromDedicatedRange && vlanUse == VlanType.VirtualNetwork) { + // Verify if account is allowed to acquire IPs from the system + boolean useSystemIps = UseSystemPublicIps.valueIn(owner.getId()); + if (useSystemIps && !nonDedicatedVlanDbIds.isEmpty()) { + fetchFromDedicatedRange = false; + sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray()); + errorMessage.append(", vlanId id=" + Arrays.toString(nonDedicatedVlanDbIds.toArray())); + if (lockOneRow) { + addrs = _ipAddressDao.lockRows(sc, filter, true); + } else { + addrs.addAll(_ipAddressDao.search(sc, null)); + } } - return addrs; } - }); + } + + if (lockOneRow && addrs.size() == 0) { + if (podId != null) { + InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", Pod.class, podId); + // for now, we hardcode the table names, but we should ideally do a lookup for the tablename from the VO object. + ex.addProxyObject(ApiDBUtils.findPodById(podId).getUuid()); + throw ex; + } + s_logger.warn(errorMessage.toString()); + InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", DataCenter.class, dcId); + ex.addProxyObject(ApiDBUtils.findZoneById(dcId).getUuid()); + throw ex; + } + + if (lockOneRow) { + assert (addrs.size() == 1) : "Return size is incorrect: " + addrs.size(); + } + + if (assign && !fetchFromDedicatedRange && VlanType.VirtualNetwork.equals(vlanUse)) { + // Check that the maximum number of public IPs for the given accountId will not be exceeded + try { + _resourceLimitMgr.checkResourceLimit(owner, ResourceType.public_ip); + } catch (ResourceAllocationException ex) { + s_logger.warn("Failed to allocate resource of type " + ex.getResourceType() + " for account " + owner); + throw new AccountLimitException("Maximum number of public IP addresses for account: " + owner.getAccountName() + " has been exceeded."); + } + } + + return addrs; } @DB diff --git a/test/integration/smoke/test_public_ip_range.py b/test/integration/smoke/test_public_ip_range.py index 69baf5f2fc21..19edc4c164f2 100644 --- a/test/integration/smoke/test_public_ip_range.py +++ b/test/integration/smoke/test_public_ip_range.py @@ -128,9 +128,8 @@ def test_dedicatePublicIpRange(self): id=self.public_ip_range.vlan.id ) public_ip_response = list_public_ip_range_response[0] - self.assertEqual( + self.assertIsNone( public_ip_response.account, - "system", "Check account name is system account in listVlanIpRanges" ) return diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index a4d0d0b6197c..6883ae9789c5 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -1739,6 +1739,7 @@ "label.suspend.project": "Suspend project", "label.switch.type": "Switch type", "label.sync.storage": "Sync storage pool", +"label.system.ip.pool": "System Pool", "label.system.offering": "System offering", "label.system.offerings": "System offerings", "label.system.service.offering": "System service offering", diff --git a/ui/src/views/infra/network/IpRangesTabPublic.vue b/ui/src/views/infra/network/IpRangesTabPublic.vue index 247a8faf0d41..d7f743fda138 100644 --- a/ui/src/views/infra/network/IpRangesTabPublic.vue +++ b/ui/src/views/infra/network/IpRangesTabPublic.vue @@ -47,21 +47,21 @@ {{ record.endip || record.endipv6 }}