Skip to content

Commit 72e3491

Browse files
authored
server: Fix allocation of more public IPs than the account's limit (#7832)
1 parent 2c60722 commit 72e3491

2 files changed

Lines changed: 86 additions & 10 deletions

File tree

server/src/main/java/com/cloud/network/IpAddressManagerImpl.java

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -991,7 +991,8 @@ public void doInTransactionWithoutResult(TransactionStatus status) {
991991
Account owner = _accountMgr.getAccount(addr.getAllocatedToAccountId());
992992
if (_ipAddressDao.lockRow(addr.getId(), true) != null) {
993993
final IPAddressVO userIp = _ipAddressDao.findById(addr.getId());
994-
if (userIp.getState() == IpAddress.State.Allocating || addr.getState() == IpAddress.State.Free) {
994+
if (userIp.getState() == IpAddress.State.Allocating || addr.getState() == IpAddress.State.Free || addr.getState() == IpAddress.State.Reserved) {
995+
boolean shouldUpdateIpResourceCount = checkIfIpResourceCountShouldBeUpdated(addr);
995996
addr.setState(IpAddress.State.Allocated);
996997
if (_ipAddressDao.update(addr.getId(), addr)) {
997998
// Save usage event
@@ -1004,7 +1005,7 @@ public void doInTransactionWithoutResult(TransactionStatus status) {
10041005
addr.getAddress().toString(), addr.isSourceNat(), guestType, addr.getSystem(), usageHidden,
10051006
addr.getClass().getName(), addr.getUuid());
10061007
}
1007-
if (updateIpResourceCount(addr)) {
1008+
if (shouldUpdateIpResourceCount) {
10081009
_resourceLimitMgr.incrementResourceCount(owner.getId(), ResourceType.public_ip);
10091010
}
10101011
}
@@ -1020,7 +1021,7 @@ public void doInTransactionWithoutResult(TransactionStatus status) {
10201021
}
10211022
}
10221023

1023-
private boolean isIpDedicated(IPAddressVO addr) {
1024+
protected boolean isIpDedicated(IPAddressVO addr) {
10241025
List<AccountVlanMapVO> maps = _accountVlanMapDao.listAccountVlanMapsByVlan(addr.getVlanId());
10251026
if (maps != null && !maps.isEmpty())
10261027
return true;
@@ -1113,7 +1114,7 @@ public boolean applyIpAssociations(Network network, boolean continueOnError) thr
11131114
// rule is applied. Similarly when last rule on the acquired IP is revoked, IP is not associated with any provider
11141115
// but still be associated with the account. At this point just mark IP as allocated or released.
11151116
for (IPAddressVO addr : userIps) {
1116-
if (addr.getState() == IpAddress.State.Allocating) {
1117+
if (addr.getState() == IpAddress.State.Allocating || addr.getState() == IpAddress.State.Reserved) {
11171118
addr.setAssociatedWithNetworkId(network.getId());
11181119
markPublicIpAsAllocated(addr);
11191120
} else if (addr.getState() == IpAddress.State.Releasing) {
@@ -1510,7 +1511,6 @@ public IPAddressVO associateIPToGuestNetwork(long ipId, long networkId, boolean
15101511

15111512
IPAddressVO ip = _ipAddressDao.findById(ipId);
15121513
//update ip address with networkId
1513-
ip.setState(State.Allocated);
15141514
ip.setAssociatedWithNetworkId(networkId);
15151515
ip.setSourceNat(isSourceNat);
15161516
_ipAddressDao.update(ipId, ip);
@@ -1523,7 +1523,7 @@ public IPAddressVO associateIPToGuestNetwork(long ipId, long networkId, boolean
15231523
} else {
15241524
s_logger.warn("Failed to associate ip address " + ip.getAddress().addr() + " to network " + network);
15251525
}
1526-
return ip;
1526+
return _ipAddressDao.findById(ipId);
15271527
} finally {
15281528
if (!success && releaseOnFailure) {
15291529
if (ip != null) {
@@ -1919,7 +1919,7 @@ public IPAddressVO markIpAsUnavailable(final long addrId) {
19191919
return Transaction.execute(new TransactionCallback<IPAddressVO>() {
19201920
@Override
19211921
public IPAddressVO doInTransaction(TransactionStatus status) {
1922-
if (updateIpResourceCount(ip)) {
1922+
if (checkIfIpResourceCountShouldBeUpdated(ip)) {
19231923
_resourceLimitMgr.decrementResourceCount(_ipAddressDao.findById(addrId).getAllocatedToAccountId(), ResourceType.public_ip);
19241924
}
19251925

@@ -1944,9 +1944,26 @@ public IPAddressVO doInTransaction(TransactionStatus status) {
19441944
return ip;
19451945
}
19461946

1947-
protected boolean updateIpResourceCount(IPAddressVO ip) {
1948-
// don't increment resource count for direct and dedicated ip addresses
1949-
return (ip.getAssociatedWithNetworkId() != null || ip.getVpcId() != null) && !isIpDedicated(ip);
1947+
protected boolean checkIfIpResourceCountShouldBeUpdated(IPAddressVO ip) {
1948+
boolean isDirectIp = ip.getAssociatedWithNetworkId() == null && ip.getVpcId() == null;
1949+
if (isDirectIp) {
1950+
s_logger.debug(String.format("IP address [%s] is direct; therefore, the resource count should not be updated.", ip));
1951+
return false;
1952+
}
1953+
1954+
if (isIpDedicated(ip)) {
1955+
s_logger.debug(String.format("IP address [%s] is dedicated; therefore, the resource count should not be updated.", ip));
1956+
return false;
1957+
}
1958+
1959+
boolean isReservedIp = ip.getState() == IpAddress.State.Reserved;
1960+
if (isReservedIp) {
1961+
s_logger.debug(String.format("IP address [%s] is reserved; therefore, the resource count should not be updated.", ip));
1962+
return false;
1963+
}
1964+
1965+
s_logger.debug(String.format("IP address [%s] is not direct, dedicated or reserved; therefore, the resource count should be updated.", ip));
1966+
return true;
19501967
}
19511968

19521969
@Override

server/src/test/java/com/cloud/network/IpAddressManagerTest.java

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ public class IpAddressManagerTest {
6565
@Mock
6666
NetworkOfferingDao networkOfferingDao;
6767

68+
@Mock
69+
IPAddressVO ipAddressVoMock;
70+
6871
@Spy
6972
@InjectMocks
7073
IpAddressManagerImpl ipAddressManager;
@@ -230,4 +233,60 @@ private Network setTestIsIpEqualsGatewayOrNetworkOfferingsEmpty(long networkOffe
230233
return network;
231234
}
232235

236+
private void prepareForCheckIfIpResourceCountShouldBeUpdatedTests() {
237+
Mockito.when(ipAddressVoMock.getAssociatedWithNetworkId()).thenReturn(1L);
238+
Mockito.when(ipAddressVoMock.getVpcId()).thenReturn(1L);
239+
doReturn(false).when(ipAddressManager).isIpDedicated(Mockito.any());
240+
Mockito.when(ipAddressVoMock.getState()).thenReturn(IpAddress.State.Allocating);
241+
}
242+
243+
@Test
244+
public void checkIfIpResourceCountShouldBeUpdatedTestIpIsDirectReturnFalse() {
245+
prepareForCheckIfIpResourceCountShouldBeUpdatedTests();
246+
Mockito.when(ipAddressVoMock.getAssociatedWithNetworkId()).thenReturn(null);
247+
Mockito.when(ipAddressVoMock.getVpcId()).thenReturn(null);
248+
249+
boolean result = ipAddressManager.checkIfIpResourceCountShouldBeUpdated(ipAddressVoMock);
250+
251+
Assert.assertFalse(result);
252+
}
253+
254+
@Test
255+
public void checkIfIpResourceCountShouldBeUpdatedTestIpIsDedicatedReturnFalse() {
256+
prepareForCheckIfIpResourceCountShouldBeUpdatedTests();
257+
doReturn(true).when(ipAddressManager).isIpDedicated(Mockito.any());
258+
259+
boolean result = ipAddressManager.checkIfIpResourceCountShouldBeUpdated(ipAddressVoMock);
260+
261+
Assert.assertFalse(result);
262+
}
263+
264+
@Test
265+
public void checkIfIpResourceCountShouldBeUpdatedTestIpIsReservedReturnFalse() {
266+
prepareForCheckIfIpResourceCountShouldBeUpdatedTests();
267+
Mockito.when(ipAddressVoMock.getState()).thenReturn(IpAddress.State.Reserved);
268+
269+
boolean result = ipAddressManager.checkIfIpResourceCountShouldBeUpdated(ipAddressVoMock);
270+
271+
Assert.assertFalse(result);
272+
}
273+
274+
@Test
275+
public void checkIfIpResourceCountShouldBeUpdatedTestIpIsAssociatedToNetworkAndNotDedicatedAndNotReservedReturnTrue() {
276+
prepareForCheckIfIpResourceCountShouldBeUpdatedTests();
277+
278+
boolean result = ipAddressManager.checkIfIpResourceCountShouldBeUpdated(ipAddressVoMock);
279+
280+
Assert.assertTrue(result);
281+
}
282+
283+
@Test
284+
public void checkIfIpResourceCountShouldBeUpdatedTestIpIsAssociatedToVpcAndNotDedicatedAndNotReservedReturnTrue() {
285+
prepareForCheckIfIpResourceCountShouldBeUpdatedTests();
286+
Mockito.when(ipAddressVoMock.getAssociatedWithNetworkId()).thenReturn(null);
287+
288+
boolean result = ipAddressManager.checkIfIpResourceCountShouldBeUpdated(ipAddressVoMock);
289+
290+
Assert.assertTrue(result);
291+
}
233292
}

0 commit comments

Comments
 (0)