This is an automated email from the ASF dual-hosted git repository.

sureshanaparti pushed a commit to branch 4.22
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/4.22 by this push:
     new b92ab08e690 Fix listPublicIpAddresses NPE on shared networks with a VR 
(#14249)
b92ab08e690 is described below

commit b92ab08e6900920f6c8dde9e644e51c950ff80c6
Author: MitchDrage <[email protected]>
AuthorDate: Mon Oct 26 15:21:45 2026 +1100

    Fix listPublicIpAddresses NPE on shared networks with a VR (#14249)
    
    * Fix listPublicIpAddresses NPE on shared network router placeholder NICs 
(#14248)
    
    * Get the router's real NIC when the shared network IP lookup returns its 
placeholder
---
 server/src/main/java/com/cloud/api/ApiDBUtils.java |  4 ++
 .../main/java/com/cloud/api/ApiResponseHelper.java | 20 ++++++---
 .../java/com/cloud/api/ApiResponseHelperTest.java  | 51 ++++++++++++++++++++++
 3 files changed, 69 insertions(+), 6 deletions(-)

diff --git a/server/src/main/java/com/cloud/api/ApiDBUtils.java 
b/server/src/main/java/com/cloud/api/ApiDBUtils.java
index c74f2ee536f..afd460a5749 100644
--- a/server/src/main/java/com/cloud/api/ApiDBUtils.java
+++ b/server/src/main/java/com/cloud/api/ApiDBUtils.java
@@ -2311,6 +2311,10 @@ public class ApiDBUtils {
         return s_nicDao.findByIp4AddressAndNetworkId(ip4Address, networkId);
     }
 
+    public static NicVO findNonPlaceHolderByIp4AddressAndNetworkId(String 
ip4Address, long networkId) {
+        return s_nicDao.findNonPlaceHolderByIp4AddressAndNetworkId(ip4Address, 
networkId);
+    }
+
     public static NicSecondaryIpVO 
findSecondaryIpByIp4AddressAndNetworkId(String ip4Address, long networkId) {
         return s_nicSecondaryIpDao.findByIp4AddressAndNetworkId(ip4Address, 
networkId);
     }
diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java 
b/server/src/main/java/com/cloud/api/ApiResponseHelper.java
index 9cf1304e292..3b09e7a2f18 100644
--- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java
@@ -1235,7 +1235,7 @@ public class ApiResponseHelper implements 
ResponseGenerator, ResourceIdSupport {
         }
     }
 
-    private void showVmInfoForSharedNetworks(boolean forVirtualNetworks, 
IpAddress ipAddr, IPAddressResponse ipResponse) {
+    protected void showVmInfoForSharedNetworks(boolean forVirtualNetworks, 
IpAddress ipAddr, IPAddressResponse ipResponse) {
         if (!forVirtualNetworks) {
             NicVO nic = 
ApiDBUtils.findByIp4AddressAndNetworkId(ipAddr.getAddress().toString(), 
ipAddr.getNetworkId());
 
@@ -1266,11 +1266,19 @@ public class ApiResponseHelper implements 
ResponseGenerator, ResourceIdSupport {
                     }
                 }
             } else if (nic.getVmType() == Type.DomainRouter) {
-                VirtualMachine vm = 
ApiDBUtils.findVMInstanceById(nic.getInstanceId());
-                if (vm != null) {
-                    ipResponse.setVirtualMachineId(vm.getUuid());
-                    ipResponse.setVirtualMachineName(vm.getHostName());
-                    ipResponse.setVirtualMachineType(vm.getType().toString());
+                ipResponse.setIsSystem(true);
+                // The lookup above returns either the router's nic or its 
placeholder, whichever the db returns first.
+                NicVO routerNic = nic;
+                if (nic.getReservationStrategy() == 
Nic.ReservationStrategy.PlaceHolder) {  // found a placeholder nic, get the 
router's real nic
+                    routerNic = 
ApiDBUtils.findNonPlaceHolderByIp4AddressAndNetworkId(ipAddr.getAddress().toString(),
 ipAddr.getNetworkId());
+                }
+                if (routerNic != null) {  // continue if we have the router's 
real nic, i.e. the router exists
+                    VirtualMachine vm = 
ApiDBUtils.findVMInstanceById(routerNic.getInstanceId());
+                    if (vm != null) {
+                        ipResponse.setVirtualMachineId(vm.getUuid());
+                        ipResponse.setVirtualMachineName(vm.getHostName());
+                        
ipResponse.setVirtualMachineType(vm.getType().toString());
+                    }
                 }
             } else if (nic.getVmType().isUsedBySystem()) {
                 ipResponse.setIsSystem(true);
diff --git a/server/src/test/java/com/cloud/api/ApiResponseHelperTest.java 
b/server/src/test/java/com/cloud/api/ApiResponseHelperTest.java
index 223b0740cf2..0a9afbc224b 100644
--- a/server/src/test/java/com/cloud/api/ApiResponseHelperTest.java
+++ b/server/src/test/java/com/cloud/api/ApiResponseHelperTest.java
@@ -42,6 +42,7 @@ import 
org.apache.cloudstack.api.response.AutoScaleVmGroupResponse;
 import org.apache.cloudstack.api.response.AutoScaleVmProfileResponse;
 import org.apache.cloudstack.api.response.DirectDownloadCertificateResponse;
 import org.apache.cloudstack.api.response.GuestOSCategoryResponse;
+import org.apache.cloudstack.api.response.IPAddressResponse;
 import org.apache.cloudstack.api.response.IpQuarantineResponse;
 import org.apache.cloudstack.api.response.NicSecondaryIpResponse;
 import org.apache.cloudstack.api.response.ResourceIconResponse;
@@ -68,6 +69,7 @@ import com.cloud.capacity.Capacity;
 import com.cloud.configuration.Resource;
 import com.cloud.domain.DomainVO;
 import com.cloud.host.HostVO;
+import com.cloud.network.IpAddress;
 import com.cloud.network.PublicIpQuarantine;
 import com.cloud.network.as.AutoScaleVmGroup;
 import com.cloud.network.as.AutoScaleVmGroupVO;
@@ -95,8 +97,11 @@ import com.cloud.user.UserVO;
 import com.cloud.user.dao.UserDataDao;
 import com.cloud.utils.net.Ip;
 import com.cloud.vm.ConsoleSessionVO;
+import com.cloud.vm.Nic;
 import com.cloud.vm.NicSecondaryIp;
+import com.cloud.vm.NicVO;
 import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.VirtualMachine;
 import org.apache.cloudstack.api.ResponseObject;
 import org.apache.cloudstack.api.response.ConsoleSessionResponse;
 
@@ -759,4 +764,50 @@ public class ApiResponseHelperTest {
             Assert.assertEquals(expected.getVmName(), response.getVmName());
         }
     }
+
+    @Test
+    public void showVmInfoForSharedNetworksTestRouterIp() {
+        IpAddress ipAddress = Mockito.mock(IpAddress.class);
+        when(ipAddress.getAddress()).thenReturn(new Ip("10.1.1.2"));
+        when(ipAddress.getNetworkId()).thenReturn(1L);
+        NicVO placeholderNic = new NicVO(null, null, 1L, 
VirtualMachine.Type.DomainRouter);
+        
placeholderNic.setReservationStrategy(Nic.ReservationStrategy.PlaceHolder);
+        NicVO routerNic = new NicVO("DirectNetworkGuru", 2L, 1L, 
VirtualMachine.Type.DomainRouter);
+        IPAddressResponse ipResponse = Mockito.mock(IPAddressResponse.class);
+
+        try (MockedStatic<ApiDBUtils> ignored = 
Mockito.mockStatic(ApiDBUtils.class)) {
+            when(ApiDBUtils.findByIp4AddressAndNetworkId("10.1.1.2", 
1L)).thenReturn(placeholderNic);
+            
when(ApiDBUtils.findNonPlaceHolderByIp4AddressAndNetworkId("10.1.1.2", 
1L)).thenReturn(routerNic);
+            
when(ApiDBUtils.findVMInstanceById(2L)).thenReturn(vmInstanceVOMock);
+            when(vmInstanceVOMock.getUuid()).thenReturn("router-uuid");
+            when(vmInstanceVOMock.getHostName()).thenReturn("r-2-VM");
+            
when(vmInstanceVOMock.getType()).thenReturn(VirtualMachine.Type.DomainRouter);
+
+            apiResponseHelper.showVmInfoForSharedNetworks(false, ipAddress, 
ipResponse);
+
+            verify(ipResponse).setIsSystem(true);
+            verify(ipResponse).setVirtualMachineId("router-uuid");
+            verify(ipResponse).setVirtualMachineName("r-2-VM");
+        }
+    }
+
+    @Test
+    public void showVmInfoForSharedNetworksTestRouterPlaceholderOnly() {
+        IpAddress ipAddress = Mockito.mock(IpAddress.class);
+        when(ipAddress.getAddress()).thenReturn(new Ip("10.1.1.2"));
+        when(ipAddress.getNetworkId()).thenReturn(1L);
+        NicVO placeholderNic = new NicVO(null, null, 1L, 
VirtualMachine.Type.DomainRouter);
+        
placeholderNic.setReservationStrategy(Nic.ReservationStrategy.PlaceHolder);
+        IPAddressResponse ipResponse = Mockito.mock(IPAddressResponse.class);
+
+        try (MockedStatic<ApiDBUtils> ignored = 
Mockito.mockStatic(ApiDBUtils.class)) {
+            
when(ApiDBUtils.findNonPlaceHolderByIp4AddressAndNetworkId("10.1.1.2", 
1L)).thenReturn(null);
+            when(ApiDBUtils.findByIp4AddressAndNetworkId("10.1.1.2", 
1L)).thenReturn(placeholderNic);
+
+            apiResponseHelper.showVmInfoForSharedNetworks(false, ipAddress, 
ipResponse);
+
+            verify(ipResponse).setIsSystem(true);
+            verify(ipResponse, 
Mockito.never()).setVirtualMachineId(Mockito.anyString());
+        }
+    }
 }

Reply via email to