From a0fe78d0184b0fe49aa8b86e2c6b7fb877d62928 Mon Sep 17 00:00:00 2001 From: Ramgopal Nagaboina Date: Tue, 1 Sep 2026 12:45:20 -0400 Subject: [PATCH] server: null-check public IP before the DNS/Source NAT guard in createPublicLoadBalancerRule createPublicLoadBalancerRule resolved ipVO only when an ipAddrId was supplied, then at the port-53 check did (srcPortStart == DNS_PORT && ipVO.isSourceNat()). For an elastic-LB rule created without an explicit IP (ipAddrId == null) the system IP is allocated later, so ipVO was still null and creating a rule on port 53 threw a NullPointerException. The ipVO == null validation only runs further down. Guard the check with ipVO != null so the DNS/Source NAT conflict test is skipped when there is no IP yet; the flow then reaches the existing can't-find-source-IP parameter error. Adds a regression test creating a port-53 rule with a null ipAddrId (NullPointerException before the fix). --- .../lb/LoadBalancingRulesManagerImpl.java | 2 +- .../lb/LoadBalancingRulesManagerImplTest.java | 36 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java index 302e05dcaa2a..4283f81ffe2a 100644 --- a/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java +++ b/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java @@ -1706,7 +1706,7 @@ public LoadBalancer createPublicLoadBalancerRule(String xId, String name, String IpAddress systemIp = null; NetworkOffering off = _entityMgr.findById(NetworkOffering.class, network.getNetworkOfferingId()); - if (srcPortStart == DNS_PORT && ipVO.isSourceNat()) { + if (srcPortStart == DNS_PORT && ipVO != null && ipVO.isSourceNat()) { List offeringServices = _networkOfferingServiceDao.listByNetworkOfferingId(network.getNetworkOfferingId()); for (NetworkOfferingServiceMapVO serviceMapVo: offeringServices) { if (serviceMapVo.getService().equals(Service.Dns.getName())) { diff --git a/server/src/test/java/com/cloud/network/lb/LoadBalancingRulesManagerImplTest.java b/server/src/test/java/com/cloud/network/lb/LoadBalancingRulesManagerImplTest.java index 184c853637b6..055d3fc663ba 100644 --- a/server/src/test/java/com/cloud/network/lb/LoadBalancingRulesManagerImplTest.java +++ b/server/src/test/java/com/cloud/network/lb/LoadBalancingRulesManagerImplTest.java @@ -17,10 +17,16 @@ package com.cloud.network.lb; +import com.cloud.exception.InvalidParameterValueException; import com.cloud.network.Network; +import com.cloud.network.NetworkModel; import com.cloud.network.dao.LoadBalancerVO; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkVO; +import com.cloud.offering.NetworkOffering; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.utils.db.EntityManager; import com.cloud.utils.exception.CloudRuntimeException; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; @@ -48,6 +54,21 @@ public class LoadBalancingRulesManagerImplTest{ @Mock NetworkOrchestrationService _networkMgr; + @Mock + EntityManager _entityMgr; + + @Mock + AccountManager _accountMgr; + + @Mock + NetworkModel _networkModel; + + @Mock + NetworkVO networkMock; + + private long accountId = 10L; + private long networkId = 4L; + @Spy @InjectMocks LoadBalancingRulesManagerImpl lbr = new LoadBalancingRulesManagerImpl(); @@ -101,4 +122,19 @@ public void testGetLoadBalancerServiceProviderFail() { Network.Provider provider = lbr.getLoadBalancerServiceProvider(loadBalancerMock); } + + @Test(expected = InvalidParameterValueException.class) + public void createPublicLoadBalancerRuleWithDnsPortAndNoIpDoesNotNpe() throws Exception { + long lbOwnerId = accountId; + long networkOfferingId = 7L; + when(_accountMgr.getAccount(lbOwnerId)).thenReturn(Mockito.mock(Account.class)); + when(_networkModel.getNetwork(networkId)).thenReturn(networkMock); + when(networkMock.getNetworkOfferingId()).thenReturn(networkOfferingId); + NetworkOffering off = Mockito.mock(NetworkOffering.class); + when(_entityMgr.findById(NetworkOffering.class, networkOfferingId)).thenReturn(off); + when(off.isElasticLb()).thenReturn(false); + + lbr.createPublicLoadBalancerRule("xid", "name", "desc", 53, 53, 53, 53, + null, "tcp", "roundrobin", networkId, lbOwnerId, false, "tcp", null, null); + } }