diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApiClient.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApiClient.java index 7ad27c4a6356..74b9949d38bf 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApiClient.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApiClient.java @@ -83,6 +83,7 @@ import com.vmware.vapi.internal.protocol.client.rest.authn.BasicAuthenticationAppender; import com.vmware.vapi.protocol.HttpConfiguration; import com.vmware.vapi.std.errors.Error; +import com.vmware.vapi.std.errors.NotFound; import org.apache.cloudstack.resource.NsxLoadBalancerMember; import org.apache.cloudstack.resource.NsxNetworkRule; import org.apache.cloudstack.utils.NsxControllerUtils; @@ -96,9 +97,11 @@ import java.util.Locale; import java.util.Objects; import java.util.Optional; +import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; +import static java.util.stream.Collectors.toSet; import static org.apache.cloudstack.utils.NsxControllerUtils.getServerPoolMemberName; import static org.apache.cloudstack.utils.NsxControllerUtils.getServerPoolName; import static org.apache.cloudstack.utils.NsxControllerUtils.getServiceName; @@ -656,9 +659,19 @@ List getLbPoolMembers(List memberList, Stri public void createNsxLbServerPool(List memberList, String tier1GatewayName, String lbServerPoolName, String algorithm, String privatePort, String protocol) { try { - String activeMonitorPath = getLbActiveMonitorPath(lbServerPoolName, privatePort, protocol); List members = getLbPoolMembers(memberList, tier1GatewayName); LbPools lbPools = (LbPools) nsxService.apply(LbPools.class); + Optional nsxLbServerPool = getNsxLbServerPool(lbPools, lbServerPoolName); + // Skip if pool exists and members unchanged + if (nsxLbServerPool.isPresent()) { + List existingMembers = nsxLbServerPool + .map(LBPool::getMembers) + .orElseGet(List::of); + if (hasSamePoolMembers(existingMembers, members)) { + return; + } + } + String activeMonitorPath = getLbActiveMonitorPath(lbServerPoolName, privatePort, protocol); LBPool lbPool = new LBPool.Builder() .setId(lbServerPoolName) .setDisplayName(lbServerPoolName) @@ -676,27 +689,62 @@ public void createNsxLbServerPool(List memberList, String } } + private Optional getNsxLbServerPool(LbPools lbPools, String lbServerPoolName) { + try { + return Optional.ofNullable(lbPools.get(lbServerPoolName)); + } catch (NotFound e) { + logger.debug("Server Pool not found: {}", lbServerPoolName); + return Optional.empty(); + } + } + + private boolean hasSamePoolMembers(List existingMembers, List membersUpdate) { + Set existingMembersSet = existingMembers.stream() + .map(this::buildPoolMemberKey) + .collect(toSet()); + Set updateMembersSet = membersUpdate.stream() + .map(this::buildPoolMemberKey) + .collect(toSet()); + + return existingMembersSet.size() == updateMembersSet.size() + && existingMembersSet.containsAll(updateMembersSet); + } + + private String buildPoolMemberKey(LBPoolMember member) { + return member.getIpAddress() + ':' + member.getPort() + ':' + member.getDisplayName(); + } + private String getLbActiveMonitorPath(String lbServerPoolName, String port, String protocol) { LbMonitorProfiles lbActiveMonitor = (LbMonitorProfiles) nsxService.apply(LbMonitorProfiles.class); String lbMonitorProfileId = getActiveMonitorProfileName(lbServerPoolName, port, protocol); - if ("TCP".equals(protocol.toUpperCase(Locale.ROOT))) { - LBTcpMonitorProfile lbTcpMonitorProfile = new LBTcpMonitorProfile.Builder(TCP_MONITOR_PROFILE) - .setDisplayName(lbMonitorProfileId) - .setMonitorPort(Long.parseLong(port)) - .build(); - lbActiveMonitor.patch(lbMonitorProfileId, lbTcpMonitorProfile); - } else if ("UDP".equals(protocol.toUpperCase(Locale.ROOT))) { - LBIcmpMonitorProfile icmpMonitorProfile = new LBIcmpMonitorProfile.Builder(ICMP_MONITOR_PROFILE) - .setDisplayName(lbMonitorProfileId) - .build(); - lbActiveMonitor.patch(lbMonitorProfileId, icmpMonitorProfile); + Optional monitorProfile = getMonitorProfile(lbActiveMonitor, lbMonitorProfileId); + if (monitorProfile.isEmpty()) { + if ("TCP".equals(protocol.toUpperCase(Locale.ROOT))) { + LBTcpMonitorProfile lbTcpMonitorProfile = new LBTcpMonitorProfile.Builder(TCP_MONITOR_PROFILE) + .setDisplayName(lbMonitorProfileId) + .setMonitorPort(Long.parseLong(port)) + .build(); + lbActiveMonitor.patch(lbMonitorProfileId, lbTcpMonitorProfile); + } else if ("UDP".equals(protocol.toUpperCase(Locale.ROOT))) { + LBIcmpMonitorProfile icmpMonitorProfile = new LBIcmpMonitorProfile.Builder(ICMP_MONITOR_PROFILE) + .setDisplayName(lbMonitorProfileId) + .build(); + lbActiveMonitor.patch(lbMonitorProfileId, icmpMonitorProfile); + } + monitorProfile = getMonitorProfile(lbActiveMonitor, lbMonitorProfileId); } - - LBMonitorProfileListResult listResult = listLBActiveMonitors(lbActiveMonitor); - Optional monitorProfile = listResult.getResults().stream().filter(profile -> profile._getDataValue().getField("id").toString().equals(lbMonitorProfileId)).findFirst(); return monitorProfile.map(structure -> structure._getDataValue().getField("path").toString()).orElse(null); } + private Optional getMonitorProfile(LbMonitorProfiles lbActiveMonitor, String lbMonitorProfileId) { + try { + return Optional.ofNullable(lbActiveMonitor.get(lbMonitorProfileId)); + } catch (NotFound e) { + logger.debug("LB Monitor Profile not found: {}", lbMonitorProfileId); + return Optional.empty(); + } + } + LBMonitorProfileListResult listLBActiveMonitors(LbMonitorProfiles lbActiveMonitor) { return lbActiveMonitor.list(null, false, null, null, null, null); } @@ -735,7 +783,7 @@ public void createAndAddNsxLbVirtualServer(String tier1GatewayName, long lbId, S String lbVirtualServerName = getVirtualServerName(tier1GatewayName, lbId); String lbServiceName = getLoadBalancerName(tier1GatewayName); LbVirtualServers lbVirtualServers = (LbVirtualServers) nsxService.apply(LbVirtualServers.class); - if (Objects.nonNull(getLbVirtualServerService(lbVirtualServers, lbServiceName))) { + if (Objects.nonNull(getLbVirtualServerService(lbVirtualServers, lbVirtualServerName))) { return; } LBVirtualServer lbVirtualServer = new LBVirtualServer.Builder() diff --git a/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxApiClientTest.java b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxApiClientTest.java index f9ee8daea4bb..5f8d771f75df 100644 --- a/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxApiClientTest.java +++ b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxApiClientTest.java @@ -18,13 +18,32 @@ import com.cloud.network.Network; import com.cloud.network.SDNProviderNetworkRule; +import com.cloud.utils.exception.CloudRuntimeException; import com.vmware.nsx.cluster.Status; import com.vmware.nsx.model.ClusterStatus; import com.vmware.nsx.model.ControllerClusterStatus; +import com.vmware.nsx_policy.infra.LbAppProfiles; +import com.vmware.nsx_policy.infra.LbMonitorProfiles; +import com.vmware.nsx_policy.infra.LbPools; +import com.vmware.nsx_policy.infra.LbServices; +import com.vmware.nsx_policy.infra.LbVirtualServers; import com.vmware.nsx_policy.infra.domains.Groups; +import com.vmware.nsx_policy.model.ApiError; import com.vmware.nsx_policy.model.Group; +import com.vmware.nsx_policy.model.LBAppProfileListResult; +import com.vmware.nsx_policy.model.LBIcmpMonitorProfile; +import com.vmware.nsx_policy.model.LBService; +import com.vmware.nsx_policy.model.LBTcpMonitorProfile; +import com.vmware.nsx_policy.model.LBPool; +import com.vmware.nsx_policy.model.LBPoolMember; +import com.vmware.nsx_policy.model.LBVirtualServer; import com.vmware.nsx_policy.model.PathExpression; import com.vmware.vapi.bindings.Service; +import com.vmware.vapi.bindings.Structure; +import com.vmware.vapi.std.errors.Error; +import com.vmware.vapi.std.errors.NotFound; +import org.apache.cloudstack.resource.NsxLoadBalancerMember; +import org.apache.cloudstack.utils.NsxControllerUtils; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -36,8 +55,20 @@ import java.util.List; import java.util.function.Function; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + public class NsxApiClientTest { + private static final String TIER_1_GATEWAY_NAME = "t1"; + @Mock private Function, Service> nsxService; @Mock @@ -108,4 +139,284 @@ public void testIsNsxControllerActive() { Mockito.when(clusterStatus.getControlClusterStatus()).thenReturn(status); Assert.assertTrue(client.isNsxControllerActive()); } + + @Test + public void testCreateNsxLbServerPoolExistingMonitorProfileSkipsMonitorPatch() { + String lbServerPoolName = NsxControllerUtils.getServerPoolName(TIER_1_GATEWAY_NAME, 1L); + List memberList = List.of(new NsxLoadBalancerMember(1L, "10.0.0.1", 80)); + + LbPools lbPools = Mockito.mock(LbPools.class); + LbMonitorProfiles lbMonitorProfiles = mockLbMonitorProfiles(); + + Mockito.when(nsxService.apply(LbPools.class)).thenReturn(lbPools); + Mockito.when(lbPools.get(lbServerPoolName)).thenThrow(new NotFound(null, null)); + + client.createNsxLbServerPool(memberList, TIER_1_GATEWAY_NAME, lbServerPoolName, "roundrobin", "80", "TCP"); + + verify(lbMonitorProfiles, never()).patch(anyString(), any(LBTcpMonitorProfile.class)); + verify(lbPools).patch(eq(lbServerPoolName), any(LBPool.class)); + } + + @Test + public void testCreateNsxLbServerPoolMissingMonitorTCPProfilePerformsPatch() { + String lbServerPoolName = NsxControllerUtils.getServerPoolName(TIER_1_GATEWAY_NAME, 1L); + List memberList = List.of(new NsxLoadBalancerMember(1L, "10.0.0.1", 80)); + + LbPools lbPools = Mockito.mock(LbPools.class); + LbMonitorProfiles lbMonitorProfiles = Mockito.mock(LbMonitorProfiles.class); + Structure monitorStructure = Mockito.mock(Structure.class, Mockito.RETURNS_DEEP_STUBS); + + Mockito.when(nsxService.apply(LbPools.class)).thenReturn(lbPools); + Mockito.when(nsxService.apply(LbMonitorProfiles.class)).thenReturn(lbMonitorProfiles); + Mockito.when(lbMonitorProfiles.get(anyString())).thenThrow(new NotFound(null, null)).thenReturn(monitorStructure); + Mockito.when(monitorStructure._getDataValue().getField("path").toString()).thenReturn("/infra/lb-monitor-profiles/test"); + Mockito.when(lbPools.get(lbServerPoolName)).thenThrow(new NotFound(null, null)); + + client.createNsxLbServerPool(memberList, TIER_1_GATEWAY_NAME, lbServerPoolName, "roundrobin", "80", "TCP"); + + verify(lbMonitorProfiles).patch(anyString(), any(LBTcpMonitorProfile.class)); + verify(lbPools).patch(eq(lbServerPoolName), any(LBPool.class)); + } + + @Test + public void testCreateNsxLbServerPoolMissingMonitorUDPProfilePerformsPatch() { + String lbServerPoolName = NsxControllerUtils.getServerPoolName(TIER_1_GATEWAY_NAME, 1L); + List memberList = List.of(new NsxLoadBalancerMember(1L, "10.0.0.1", 80)); + + LbPools lbPools = Mockito.mock(LbPools.class); + LbMonitorProfiles lbMonitorProfiles = Mockito.mock(LbMonitorProfiles.class); + Structure monitorStructure = Mockito.mock(Structure.class, Mockito.RETURNS_DEEP_STUBS); + + Mockito.when(nsxService.apply(LbPools.class)).thenReturn(lbPools); + Mockito.when(nsxService.apply(LbMonitorProfiles.class)).thenReturn(lbMonitorProfiles); + Mockito.when(lbMonitorProfiles.get(anyString())).thenThrow(new NotFound(null, null)).thenReturn(monitorStructure); + Mockito.when(monitorStructure._getDataValue().getField("path").toString()).thenReturn("/infra/lb-monitor-profiles/test"); + Mockito.when(lbPools.get(lbServerPoolName)).thenThrow(new NotFound(null, null)); + + client.createNsxLbServerPool(memberList, TIER_1_GATEWAY_NAME, lbServerPoolName, "roundrobin", "80", "UDP"); + + verify(lbMonitorProfiles).patch(anyString(), any(LBIcmpMonitorProfile.class)); + verify(lbPools).patch(eq(lbServerPoolName), any(LBPool.class)); + } + + @Test + public void testCreateNsxLbServerPoolPoolExistsWithSameMembersSkipsPatch() { + long lbId = 1L; + String lbServerPoolName = NsxControllerUtils.getServerPoolName(TIER_1_GATEWAY_NAME, lbId); + List memberList = List.of( + new NsxLoadBalancerMember(1L, "10.0.0.1", 80), + new NsxLoadBalancerMember(2L, "10.0.0.2", 80) + ); + List sameMembers = List.of( + createPoolMember(2L, "10.0.0.2", 80), + createPoolMember(1L, "10.0.0.1", 80) + ); + + LbPools lbPools = Mockito.mock(LbPools.class); + LBPool existingPool = Mockito.mock(LBPool.class); + + Mockito.when(nsxService.apply(LbPools.class)).thenReturn(lbPools); + Mockito.when(lbPools.get(lbServerPoolName)).thenReturn(existingPool); + Mockito.when(existingPool.getMembers()).thenReturn(sameMembers); + + client.createNsxLbServerPool(memberList, TIER_1_GATEWAY_NAME, lbServerPoolName, "roundrobin", "80", "TCP"); + + verify(nsxService, never()).apply(LbMonitorProfiles.class); + verify(lbPools, never()).patch(anyString(), any(LBPool.class)); + } + + @Test + public void testCreateNsxLbServerPoolPoolExistsWithoutMembersAndEmptyUpdateSkipsPatch() { + String lbServerPoolName = NsxControllerUtils.getServerPoolName(TIER_1_GATEWAY_NAME, 1L); + + LbPools lbPools = Mockito.mock(LbPools.class); + LBPool existingPool = Mockito.mock(LBPool.class); + + Mockito.when(nsxService.apply(LbPools.class)).thenReturn(lbPools); + Mockito.when(lbPools.get(lbServerPoolName)).thenReturn(existingPool); + Mockito.when(existingPool.getMembers()).thenReturn(null); + + client.createNsxLbServerPool(List.of(), TIER_1_GATEWAY_NAME, lbServerPoolName, "roundrobin", "80", "TCP"); + + verify(nsxService, never()).apply(LbMonitorProfiles.class); + verify(lbPools, never()).patch(anyString(), any(LBPool.class)); + } + + @Test + public void testCreateNsxLbServerPoolPoolExistsWithDuplicateMembersSkipsPatch() { + long lbId = 1L; + String lbServerPoolName = NsxControllerUtils.getServerPoolName(TIER_1_GATEWAY_NAME, lbId); + List memberList = List.of( + new NsxLoadBalancerMember(1L, "10.0.0.1", 80), + new NsxLoadBalancerMember(2L, "10.0.0.2", 80) + ); + + LbPools lbPools = Mockito.mock(LbPools.class); + LBPool existingPool = Mockito.mock(LBPool.class); + + Mockito.when(nsxService.apply(LbPools.class)).thenReturn(lbPools); + Mockito.when(lbPools.get(lbServerPoolName)).thenReturn(existingPool); + Mockito.when(existingPool.getMembers()).thenReturn(List.of( + createPoolMember(1L, "10.0.0.1", 80), + createPoolMember(1L, "10.0.0.1", 80), + createPoolMember(2L, "10.0.0.2", 80) + )); + + client.createNsxLbServerPool(memberList, TIER_1_GATEWAY_NAME, lbServerPoolName, "roundrobin", "80", "TCP"); + + verify(nsxService, never()).apply(LbMonitorProfiles.class); + verify(lbPools, never()).patch(anyString(), any(LBPool.class)); + } + + @Test + public void testCreateNsxLbServerPoolPoolExistsWithDifferentMembersPerformsPatch() { + long lbId = 1L; + String lbServerPoolName = NsxControllerUtils.getServerPoolName(TIER_1_GATEWAY_NAME, lbId); + List memberList = List.of( + new NsxLoadBalancerMember(1L, "10.0.0.1", 80), + new NsxLoadBalancerMember(2L, "10.0.0.2", 80) + ); + + LbPools lbPools = Mockito.mock(LbPools.class); + LBPool existingPool = Mockito.mock(LBPool.class); + + mockLbMonitorProfiles(); + Mockito.when(nsxService.apply(LbPools.class)).thenReturn(lbPools); + Mockito.when(lbPools.get(lbServerPoolName)).thenReturn(existingPool); + Mockito.when(existingPool.getMembers()).thenReturn(List.of( + createPoolMember(1L, "10.0.0.10", 80) + )); + + client.createNsxLbServerPool(memberList, TIER_1_GATEWAY_NAME, lbServerPoolName, "roundrobin", "80", "TCP"); + + verify(lbPools).patch(eq(lbServerPoolName), any(LBPool.class)); + } + + @Test + public void testCreateNsxLbServerPoolPoolDoesNotExistPerformsPatch() { + String lbServerPoolName = NsxControllerUtils.getServerPoolName(TIER_1_GATEWAY_NAME, 1L); + List memberList = List.of(new NsxLoadBalancerMember(1L, "10.0.0.1", 80)); + + LbPools lbPools = Mockito.mock(LbPools.class); + + mockLbMonitorProfiles(); + Mockito.when(nsxService.apply(LbPools.class)).thenReturn(lbPools); + Mockito.when(lbPools.get(lbServerPoolName)).thenThrow(new NotFound(null, null)); + + client.createNsxLbServerPool(memberList, TIER_1_GATEWAY_NAME, lbServerPoolName, "roundrobin", "80", "TCP"); + + verify(lbPools).patch(eq(lbServerPoolName), any(LBPool.class)); + } + + @Test + public void testCreateAndAddNsxLbVirtualServerVirtualServerAlreadyExistsSkipsPatch() { + long lbId = 1L; + String lbVirtualServerName = NsxControllerUtils.getVirtualServerName(TIER_1_GATEWAY_NAME, lbId); + String lbServiceName = NsxControllerUtils.getLoadBalancerName(TIER_1_GATEWAY_NAME); + List memberList = List.of(new NsxLoadBalancerMember(1L, "10.0.0.1", 80)); + + LbPools lbPools = Mockito.mock(LbPools.class); + LbServices lbServices = Mockito.mock(LbServices.class); + LbVirtualServers lbVirtualServers = Mockito.mock(LbVirtualServers.class); + LBVirtualServer existingVs = Mockito.mock(LBVirtualServer.class); + + mockLbMonitorProfiles(); + Mockito.when(nsxService.apply(LbPools.class)).thenReturn(lbPools); + Mockito.when(nsxService.apply(LbServices.class)).thenReturn(lbServices); + Mockito.when(nsxService.apply(LbVirtualServers.class)).thenReturn(lbVirtualServers); + Mockito.when(lbPools.get(anyString())).thenThrow(new NotFound(null, null)); + Mockito.when(lbServices.get(anyString())).thenReturn(null); + Mockito.when(lbVirtualServers.get(lbVirtualServerName)).thenReturn(existingVs); + + client.createAndAddNsxLbVirtualServer(TIER_1_GATEWAY_NAME, lbId, "192.168.1.1", "443", + memberList, "roundrobin", "TCP", "80"); + + verify(lbVirtualServers).get(lbVirtualServerName); + verify(lbVirtualServers, never()).get(lbServiceName); + verify(lbVirtualServers, never()).patch(anyString(), any(LBVirtualServer.class)); + } + + @Test + public void testCreateAndAddNsxLbVirtualServerVirtualServerNotFoundPerformsPatch() { + long lbId = 1L; + String lbServerPoolName = NsxControllerUtils.getServerPoolName(TIER_1_GATEWAY_NAME, lbId); + String lbVirtualServerName = NsxControllerUtils.getVirtualServerName(TIER_1_GATEWAY_NAME, lbId); + String lbServiceName = NsxControllerUtils.getLoadBalancerName(TIER_1_GATEWAY_NAME); + List memberList = List.of(new NsxLoadBalancerMember(1L, "10.0.0.1", 80)); + + LbPools lbPools = Mockito.mock(LbPools.class); + LBPool lbPool = Mockito.mock(LBPool.class); + LbServices lbServices = Mockito.mock(LbServices.class); + LBService lbService = Mockito.mock(LBService.class); + LbVirtualServers lbVirtualServers = Mockito.mock(LbVirtualServers.class); + + mockLbMonitorProfiles(); + mockLbAppProfiles(); + Mockito.when(nsxService.apply(LbPools.class)).thenReturn(lbPools); + Mockito.when(nsxService.apply(LbServices.class)).thenReturn(lbServices); + Mockito.when(nsxService.apply(LbVirtualServers.class)).thenReturn(lbVirtualServers); + Mockito.when(lbPools.get(lbServerPoolName)).thenThrow(new NotFound(null, null)).thenReturn(lbPool); + Mockito.when(lbPool.getPath()).thenReturn("/infra/lb-pools/" + lbServerPoolName); + Mockito.when(lbServices.get(lbServiceName)).thenReturn(lbService); + Mockito.when(lbService.getPath()).thenReturn("/infra/lb-services/" + lbServiceName); + Mockito.when(lbVirtualServers.get(lbVirtualServerName)).thenThrow(new NotFound(null, null)); + + client.createAndAddNsxLbVirtualServer(TIER_1_GATEWAY_NAME, lbId, "192.168.1.1", "443", + memberList, "roundrobin", "TCP", "80"); + + verify(lbVirtualServers).get(lbVirtualServerName); + verify(lbVirtualServers, never()).get(lbServiceName); + verify(lbVirtualServers).patch(eq(lbVirtualServerName), any(LBVirtualServer.class)); + } + + @Test + public void testCreateNsxLbServerPoolThrowsExceptionOnPatchError() { + String lbServerPoolName = NsxControllerUtils.getServerPoolName(TIER_1_GATEWAY_NAME, 1L); + List memberList = List.of(new NsxLoadBalancerMember(1L, "10.0.0.1", 80)); + + LbPools lbPools = Mockito.mock(LbPools.class); + Structure errorData = Mockito.mock(Structure.class); + ApiError apiError = new ApiError(); + apiError.setErrorData(errorData); + + mockLbMonitorProfiles(); + Mockito.when(nsxService.apply(LbPools.class)).thenReturn(lbPools); + Mockito.when(lbPools.get(lbServerPoolName)).thenThrow(new NotFound(null, null)); + when(errorData._convertTo(ApiError.class)).thenReturn(apiError); + doThrow(new Error(List.of(), errorData)).when(lbPools).patch(eq(lbServerPoolName), any(LBPool.class)); + + CloudRuntimeException thrownException = assertThrows(CloudRuntimeException.class, () -> { + client.createNsxLbServerPool(memberList, TIER_1_GATEWAY_NAME, lbServerPoolName, "roundrobin", "80", "TCP"); + }); + assertTrue(thrownException.getMessage().startsWith("Failed to create NSX LB server pool, due to")); + } + + private LbMonitorProfiles mockLbMonitorProfiles() { + LbMonitorProfiles lbMonitorProfiles = Mockito.mock(LbMonitorProfiles.class); + Structure monitorStructure = Mockito.mock(Structure.class, Mockito.RETURNS_DEEP_STUBS); + + Mockito.when(nsxService.apply(LbMonitorProfiles.class)).thenReturn(lbMonitorProfiles); + Mockito.when(lbMonitorProfiles.get(anyString())).thenReturn(monitorStructure); + Mockito.when(monitorStructure._getDataValue().getField("path").toString()).thenReturn("/infra/lb-monitor-profiles/test"); + return lbMonitorProfiles; + } + + private void mockLbAppProfiles() { + LbAppProfiles lbAppProfiles = Mockito.mock(LbAppProfiles.class); + LBAppProfileListResult appProfileListResult = Mockito.mock(LBAppProfileListResult.class); + Structure appProfile = Mockito.mock(Structure.class, Mockito.RETURNS_DEEP_STUBS); + + Mockito.when(nsxService.apply(LbAppProfiles.class)).thenReturn(lbAppProfiles); + Mockito.when(lbAppProfiles.list(null, null, null, null, null, null)).thenReturn(appProfileListResult); + Mockito.when(appProfileListResult.getResults()).thenReturn(List.of(appProfile)); + Mockito.when(appProfile._getDataValue().getField("path").toString()).thenReturn("/infra/lb-app-profiles/default-tcp-profile"); + } + + private LBPoolMember createPoolMember(long vmId, String ipAddress, int port) { + return new LBPoolMember.Builder() + .setDisplayName(NsxControllerUtils.getServerPoolMemberName(TIER_1_GATEWAY_NAME, vmId)) + .setIpAddress(ipAddress) + .setPort(String.valueOf(port)) + .build(); + } }