Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -190,4 +190,6 @@ List<VMInstanceVO> searchRemovedByRemoveDate(final Date startDate, final Date en
int getVmCountByOfferingId(Long serviceOfferingId);

int getVmCountByOfferingNotInDomain(Long serviceOfferingId, List<Long> domainIds);

List<VMInstanceVO> listByIds(List<Long> ids);
}
Original file line number Diff line number Diff line change
Expand Up @@ -1261,4 +1261,17 @@ public int getVmCountByOfferingNotInDomain(Long serviceOfferingId, List<Long> do
List<Integer> count = customSearch(sc, null);
return count.get(0);
}

@Override
public List<VMInstanceVO> listByIds(List<Long> ids) {
if (ids == null || ids.isEmpty()) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CollectionUtils ?

return new ArrayList<>();
}
SearchBuilder<VMInstanceVO> sb = createSearchBuilder();
sb.and("id", sb.entity().getId(), Op.IN);
sb.done();
SearchCriteria<VMInstanceVO> sc = sb.create();
sc.setParameters("id", ids.toArray());
return listBy(sc);
}
}
6 changes: 5 additions & 1 deletion server/src/main/java/com/cloud/network/NetworkModelImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -965,7 +965,11 @@ public boolean isSharedNetworkWithoutServices (long networkId) {

Network network = _networksDao.findById(networkId);

if (network != null && network.getGuestType() != GuestType.Shared) {
if (network == null) {
return false;
}

if (network.getGuestType() != GuestType.Shared) {
return false;
}

Expand Down
57 changes: 39 additions & 18 deletions server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;

import com.cloud.utils.Profiler;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
Expand Down Expand Up @@ -2452,33 +2453,53 @@
public boolean start() {
_executor.scheduleWithFixedDelay(new ExpungeTask(), _expungeInterval, _expungeInterval, TimeUnit.SECONDS);
_vmIpFetchExecutor.scheduleWithFixedDelay(new VmIpFetchTask(), VmIpFetchWaitInterval.value(), VmIpFetchWaitInterval.value(), TimeUnit.SECONDS);
loadVmDetailsInMapForExternalDhcpIp();
_vmIpFetchExecutor.submit(this::loadVmDetailsInMapForExternalDhcpIp);
return true;
}

private void loadVmDetailsInMapForExternalDhcpIp() {
protected void loadVmDetailsInMapForExternalDhcpIp() {
try {
Profiler profiler = new Profiler();
profiler.start();

List<NetworkVO> networks = _networkDao.listByGuestType(Network.GuestType.Shared);
Map<Long, Boolean> offeringWithoutServices = new HashMap<>();
int networksScanned = 0;
int nicsAdded = 0;

for (NetworkVO network : networks) {

Check warning on line 2470 in server/src/main/java/com/cloud/vm/UserVmManagerImpl.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Reduce the total number of break and continue statements in this loop to use at most one.

See more on https://sonarcloud.io/project/issues?id=apache_cloudstack&issues=AZ9sSQGWDqXMSY--9F0f&open=AZ9sSQGWDqXMSY--9F0f&pullRequest=13635
boolean withoutServices = offeringWithoutServices.computeIfAbsent(network.getNetworkOfferingId(),
offeringId -> _networkModel.listNetworkOfferingServices(offeringId).isEmpty());
if (!withoutServices) {
continue;
}
networksScanned++;
Comment on lines +2465 to +2476

List<NetworkVO> networks = _networkDao.listByGuestType(Network.GuestType.Shared);
networks.addAll(_networkDao.listByGuestType(Network.GuestType.L2));
List<NicVO> nullIpNics = _nicDao.listByNetworkId(network.getId()).stream()
.filter(nic -> nic.getIPv4Address() == null)
.collect(Collectors.toList());
if (nullIpNics.isEmpty()) {
continue;
}

for (NetworkVO network: networks) {
if (GuestType.L2.equals(network.getGuestType()) || _networkModel.isSharedNetworkWithoutServices(network.getId())) {
List<NicVO> nics = _nicDao.listByNetworkId(network.getId());
List<Long> vmIds = nullIpNics.stream().map(NicVO::getInstanceId).distinct().collect(Collectors.toList());
Map<Long, VMInstanceVO> runningVmsById = _vmInstanceDao.listByIds(vmIds).stream()
.filter(vm -> vm != null && vm.getState() == State.Running)
.collect(Collectors.toMap(VMInstanceVO::getId, vm -> vm));

for (NicVO nic : nics) {
if (nic.getIPv4Address() == null) {
long nicId = nic.getId();
long vmId = nic.getInstanceId();
VMInstanceVO vmInstance = _vmInstanceDao.findById(vmId);

// only load running vms. For stopped vms get loaded on starting
if (vmInstance != null && vmInstance.getState() == State.Running) {
VmAndCountDetails vmAndCount = new VmAndCountDetails(vmId, VmIpFetchTrialMax.value());
vmIdCountMap.put(nicId, vmAndCount);
}
for (NicVO nic : nullIpNics) {
if (runningVmsById.containsKey(nic.getInstanceId())) {
vmIdCountMap.put(nic.getId(), new VmAndCountDetails(nic.getInstanceId(), VmIpFetchTrialMax.value()));
nicsAdded++;
}
}
}

profiler.stop();
logger.info("External-DHCP VM-IP map seeded: {} shared-without-service networks, {} nics added, took {} ms",
networksScanned, nicsAdded, profiler.getDurationInMillis());
} catch (Exception e) {
logger.error("Failed to seed external-DHCP VM-IP retrieval map", e);
}
}

Expand Down
10 changes: 10 additions & 0 deletions server/src/test/java/com/cloud/network/NetworkModelImplTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.network.addr.PublicIp;
import com.cloud.network.dao.IPAddressVO;
import com.cloud.network.dao.NetworkDao;
import com.cloud.network.dao.NetworkServiceMapDao;
import com.cloud.network.dao.NetworkServiceMapVO;
import com.cloud.network.dao.NetworkVO;
Expand Down Expand Up @@ -232,4 +233,13 @@
Map<Network.Provider, ArrayList<PublicIpAddress>> result = networkModel.getProviderToIpList(network, ipToServices);
Assert.assertNotNull(result);
}

@Test
public void testIsSharedNetworkWithoutServicesReturnsFalseWhenNetworkMissing() {
NetworkDao networksDao = Mockito.mock(NetworkDao.class);

Check warning on line 239 in server/src/test/java/com/cloud/network/NetworkModelImplTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use a static import for "mock".

See more on https://sonarcloud.io/project/issues?id=apache_cloudstack&issues=AZ9sSQJHDqXMSY--9F0g&open=AZ9sSQJHDqXMSY--9F0g&pullRequest=13635
ReflectionTestUtils.setField(networkModel, "_networksDao", networksDao);
Mockito.when(networksDao.findById(123L)).thenReturn(null);

Check warning on line 241 in server/src/test/java/com/cloud/network/NetworkModelImplTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use a static import for "when".

See more on https://sonarcloud.io/project/issues?id=apache_cloudstack&issues=AZ9sSQJHDqXMSY--9F0h&open=AZ9sSQJHDqXMSY--9F0h&pullRequest=13635

Assert.assertFalse(networkModel.isSharedNetworkWithoutServices(123L));
}
}
61 changes: 61 additions & 0 deletions server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
Expand All @@ -45,6 +47,7 @@
import java.util.List;
import java.util.Map;

import com.cloud.vm.dao.VMInstanceDao;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.SecurityChecker;
import org.apache.cloudstack.api.ApiConstants;
Expand Down Expand Up @@ -188,6 +191,9 @@
@Mock
protected NicDao nicDao;

@Mock
protected VMInstanceDao vmInstanceDao;

@Mock
private NetworkDao _networkDao;

Expand Down Expand Up @@ -3207,4 +3213,59 @@
userVmManagerImpl.verifyVmLimits(userVmVoMock, customParameters));
Assert.assertTrue(ex.getMessage().startsWith("The CPU speed of this offering"));
}

@Test
public void testLoadVmDetailsInMapForExternalDhcpIpSeedsOnlyRunningNullIpNics() {
NetworkVO network = mock(NetworkVO.class);
when(network.getId()).thenReturn(100L);
when(network.getNetworkOfferingId()).thenReturn(7L);
when(_networkDao.listByGuestType(Network.GuestType.Shared)).thenReturn(Arrays.asList(network));
when(networkModel.listNetworkOfferingServices(7L)).thenReturn(new ArrayList<>());

NicVO runningNullIp = mock(NicVO.class);
when(runningNullIp.getId()).thenReturn(11L);
when(runningNullIp.getInstanceId()).thenReturn(1000L);
when(runningNullIp.getIPv4Address()).thenReturn(null);

NicVO withIp = mock(NicVO.class);
when(withIp.getIPv4Address()).thenReturn("10.1.1.5");

NicVO stoppedNullIp = mock(NicVO.class);
when(stoppedNullIp.getInstanceId()).thenReturn(2000L);
when(stoppedNullIp.getIPv4Address()).thenReturn(null);

when(nicDao.listByNetworkId(100L)).thenReturn(Arrays.asList(runningNullIp, withIp, stoppedNullIp));

VMInstanceVO running = mock(VMInstanceVO.class);
when(running.getId()).thenReturn(1000L);
when(running.getState()).thenReturn(VirtualMachine.State.Running);
VMInstanceVO stopped = mock(VMInstanceVO.class);
when(stopped.getState()).thenReturn(VirtualMachine.State.Stopped);
when(vmInstanceDao.listByIds(Mockito.anyList())).thenReturn(Arrays.asList(running, stopped));

userVmManagerImpl.loadVmDetailsInMapForExternalDhcpIp();

@SuppressWarnings("unchecked")
Map<Long, ?> vmIdCountMap = (Map<Long, ?>) ReflectionTestUtils.getField(userVmManagerImpl, "vmIdCountMap");
assertNotNull(vmIdCountMap);
assertEquals(1, vmIdCountMap.size());
assertTrue(vmIdCountMap.containsKey(11L));
assertFalse(vmIdCountMap.containsKey(12L));
Mockito.verify(vmInstanceDao, times(1)).listByIds(Mockito.anyList());

Check warning on line 3254 in server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use a static import for "verify".

See more on https://sonarcloud.io/project/issues?id=apache_cloudstack&issues=AZ9sSQMnDqXMSY--9F0i&open=AZ9sSQMnDqXMSY--9F0i&pullRequest=13635
Mockito.verify(vmInstanceDao, Mockito.never()).findById(Mockito.anyLong());

Check warning on line 3255 in server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use a static import for "never".

See more on https://sonarcloud.io/project/issues?id=apache_cloudstack&issues=AZ9sSQMnDqXMSY--9F0k&open=AZ9sSQMnDqXMSY--9F0k&pullRequest=13635

Check warning on line 3255 in server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use a static import for "verify".

See more on https://sonarcloud.io/project/issues?id=apache_cloudstack&issues=AZ9sSQMnDqXMSY--9F0j&open=AZ9sSQMnDqXMSY--9F0j&pullRequest=13635
}

@Test
public void testStartSeedsExternalDhcpMapAsynchronously() {
java.util.concurrent.ScheduledExecutorService expungeExecutor = mock(java.util.concurrent.ScheduledExecutorService.class);
java.util.concurrent.ScheduledExecutorService ipFetchExecutor = mock(java.util.concurrent.ScheduledExecutorService.class);
ReflectionTestUtils.setField(userVmManagerImpl, "_executor", expungeExecutor);
ReflectionTestUtils.setField(userVmManagerImpl, "_vmIpFetchExecutor", ipFetchExecutor);

boolean result = userVmManagerImpl.start();

assertTrue(result);
Mockito.verify(ipFetchExecutor, times(1)).submit(any(Runnable.class));

Check warning on line 3268 in server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use a static import for "verify".

See more on https://sonarcloud.io/project/issues?id=apache_cloudstack&issues=AZ9sSQMnDqXMSY--9F0l&open=AZ9sSQMnDqXMSY--9F0l&pullRequest=13635
Mockito.verify(userVmManagerImpl, Mockito.never()).loadVmDetailsInMapForExternalDhcpIp();

Check warning on line 3269 in server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use a static import for "verify".

See more on https://sonarcloud.io/project/issues?id=apache_cloudstack&issues=AZ9sSQMnDqXMSY--9F0m&open=AZ9sSQMnDqXMSY--9F0m&pullRequest=13635

Check warning on line 3269 in server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use a static import for "never".

See more on https://sonarcloud.io/project/issues?id=apache_cloudstack&issues=AZ9sSQMnDqXMSY--9F0n&open=AZ9sSQMnDqXMSY--9F0n&pullRequest=13635
}
}
Loading