Skip to content

Commit b92ab08

Browse files
authored
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
1 parent 9872bfd commit b92ab08

3 files changed

Lines changed: 69 additions & 6 deletions

File tree

‎server/src/main/java/com/cloud/api/ApiDBUtils.java‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2311,6 +2311,10 @@ public static NicVO findByIp4AddressAndNetworkId(String ip4Address, long network
23112311
return s_nicDao.findByIp4AddressAndNetworkId(ip4Address, networkId);
23122312
}
23132313

2314+
public static NicVO findNonPlaceHolderByIp4AddressAndNetworkId(String ip4Address, long networkId) {
2315+
return s_nicDao.findNonPlaceHolderByIp4AddressAndNetworkId(ip4Address, networkId);
2316+
}
2317+
23142318
public static NicSecondaryIpVO findSecondaryIpByIp4AddressAndNetworkId(String ip4Address, long networkId) {
23152319
return s_nicSecondaryIpDao.findByIp4AddressAndNetworkId(ip4Address, networkId);
23162320
}

‎server/src/main/java/com/cloud/api/ApiResponseHelper.java‎

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,7 +1235,7 @@ private void setVpcIdInResponse(Long vpcId, Consumer<String> vpcUuidSetter, Cons
12351235
}
12361236
}
12371237

1238-
private void showVmInfoForSharedNetworks(boolean forVirtualNetworks, IpAddress ipAddr, IPAddressResponse ipResponse) {
1238+
protected void showVmInfoForSharedNetworks(boolean forVirtualNetworks, IpAddress ipAddr, IPAddressResponse ipResponse) {
12391239
if (!forVirtualNetworks) {
12401240
NicVO nic = ApiDBUtils.findByIp4AddressAndNetworkId(ipAddr.getAddress().toString(), ipAddr.getNetworkId());
12411241

@@ -1266,11 +1266,19 @@ private void showVmInfoForSharedNetworks(boolean forVirtualNetworks, IpAddress i
12661266
}
12671267
}
12681268
} else if (nic.getVmType() == Type.DomainRouter) {
1269-
VirtualMachine vm = ApiDBUtils.findVMInstanceById(nic.getInstanceId());
1270-
if (vm != null) {
1271-
ipResponse.setVirtualMachineId(vm.getUuid());
1272-
ipResponse.setVirtualMachineName(vm.getHostName());
1273-
ipResponse.setVirtualMachineType(vm.getType().toString());
1269+
ipResponse.setIsSystem(true);
1270+
// The lookup above returns either the router's nic or its placeholder, whichever the db returns first.
1271+
NicVO routerNic = nic;
1272+
if (nic.getReservationStrategy() == Nic.ReservationStrategy.PlaceHolder) { // found a placeholder nic, get the router's real nic
1273+
routerNic = ApiDBUtils.findNonPlaceHolderByIp4AddressAndNetworkId(ipAddr.getAddress().toString(), ipAddr.getNetworkId());
1274+
}
1275+
if (routerNic != null) { // continue if we have the router's real nic, i.e. the router exists
1276+
VirtualMachine vm = ApiDBUtils.findVMInstanceById(routerNic.getInstanceId());
1277+
if (vm != null) {
1278+
ipResponse.setVirtualMachineId(vm.getUuid());
1279+
ipResponse.setVirtualMachineName(vm.getHostName());
1280+
ipResponse.setVirtualMachineType(vm.getType().toString());
1281+
}
12741282
}
12751283
} else if (nic.getVmType().isUsedBySystem()) {
12761284
ipResponse.setIsSystem(true);

‎server/src/test/java/com/cloud/api/ApiResponseHelperTest.java‎

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import org.apache.cloudstack.api.response.AutoScaleVmProfileResponse;
4343
import org.apache.cloudstack.api.response.DirectDownloadCertificateResponse;
4444
import org.apache.cloudstack.api.response.GuestOSCategoryResponse;
45+
import org.apache.cloudstack.api.response.IPAddressResponse;
4546
import org.apache.cloudstack.api.response.IpQuarantineResponse;
4647
import org.apache.cloudstack.api.response.NicSecondaryIpResponse;
4748
import org.apache.cloudstack.api.response.ResourceIconResponse;
@@ -68,6 +69,7 @@
6869
import com.cloud.configuration.Resource;
6970
import com.cloud.domain.DomainVO;
7071
import com.cloud.host.HostVO;
72+
import com.cloud.network.IpAddress;
7173
import com.cloud.network.PublicIpQuarantine;
7274
import com.cloud.network.as.AutoScaleVmGroup;
7375
import com.cloud.network.as.AutoScaleVmGroupVO;
@@ -95,8 +97,11 @@
9597
import com.cloud.user.dao.UserDataDao;
9698
import com.cloud.utils.net.Ip;
9799
import com.cloud.vm.ConsoleSessionVO;
100+
import com.cloud.vm.Nic;
98101
import com.cloud.vm.NicSecondaryIp;
102+
import com.cloud.vm.NicVO;
99103
import com.cloud.vm.VMInstanceVO;
104+
import com.cloud.vm.VirtualMachine;
100105
import org.apache.cloudstack.api.ResponseObject;
101106
import org.apache.cloudstack.api.response.ConsoleSessionResponse;
102107

@@ -759,4 +764,50 @@ public void createConsoleSessionResponseTestShouldReturnFullResponse() {
759764
Assert.assertEquals(expected.getVmName(), response.getVmName());
760765
}
761766
}
767+
768+
@Test
769+
public void showVmInfoForSharedNetworksTestRouterIp() {
770+
IpAddress ipAddress = Mockito.mock(IpAddress.class);
771+
when(ipAddress.getAddress()).thenReturn(new Ip("10.1.1.2"));
772+
when(ipAddress.getNetworkId()).thenReturn(1L);
773+
NicVO placeholderNic = new NicVO(null, null, 1L, VirtualMachine.Type.DomainRouter);
774+
placeholderNic.setReservationStrategy(Nic.ReservationStrategy.PlaceHolder);
775+
NicVO routerNic = new NicVO("DirectNetworkGuru", 2L, 1L, VirtualMachine.Type.DomainRouter);
776+
IPAddressResponse ipResponse = Mockito.mock(IPAddressResponse.class);
777+
778+
try (MockedStatic<ApiDBUtils> ignored = Mockito.mockStatic(ApiDBUtils.class)) {
779+
when(ApiDBUtils.findByIp4AddressAndNetworkId("10.1.1.2", 1L)).thenReturn(placeholderNic);
780+
when(ApiDBUtils.findNonPlaceHolderByIp4AddressAndNetworkId("10.1.1.2", 1L)).thenReturn(routerNic);
781+
when(ApiDBUtils.findVMInstanceById(2L)).thenReturn(vmInstanceVOMock);
782+
when(vmInstanceVOMock.getUuid()).thenReturn("router-uuid");
783+
when(vmInstanceVOMock.getHostName()).thenReturn("r-2-VM");
784+
when(vmInstanceVOMock.getType()).thenReturn(VirtualMachine.Type.DomainRouter);
785+
786+
apiResponseHelper.showVmInfoForSharedNetworks(false, ipAddress, ipResponse);
787+
788+
verify(ipResponse).setIsSystem(true);
789+
verify(ipResponse).setVirtualMachineId("router-uuid");
790+
verify(ipResponse).setVirtualMachineName("r-2-VM");
791+
}
792+
}
793+
794+
@Test
795+
public void showVmInfoForSharedNetworksTestRouterPlaceholderOnly() {
796+
IpAddress ipAddress = Mockito.mock(IpAddress.class);
797+
when(ipAddress.getAddress()).thenReturn(new Ip("10.1.1.2"));
798+
when(ipAddress.getNetworkId()).thenReturn(1L);
799+
NicVO placeholderNic = new NicVO(null, null, 1L, VirtualMachine.Type.DomainRouter);
800+
placeholderNic.setReservationStrategy(Nic.ReservationStrategy.PlaceHolder);
801+
IPAddressResponse ipResponse = Mockito.mock(IPAddressResponse.class);
802+
803+
try (MockedStatic<ApiDBUtils> ignored = Mockito.mockStatic(ApiDBUtils.class)) {
804+
when(ApiDBUtils.findNonPlaceHolderByIp4AddressAndNetworkId("10.1.1.2", 1L)).thenReturn(null);
805+
when(ApiDBUtils.findByIp4AddressAndNetworkId("10.1.1.2", 1L)).thenReturn(placeholderNic);
806+
807+
apiResponseHelper.showVmInfoForSharedNetworks(false, ipAddress, ipResponse);
808+
809+
verify(ipResponse).setIsSystem(true);
810+
verify(ipResponse, Mockito.never()).setVirtualMachineId(Mockito.anyString());
811+
}
812+
}
762813
}

0 commit comments

Comments
 (0)