sonar remarks addressed and some extra tests generated

This commit is contained in:
Daan Hoogland 2026-04-17 11:14:12 +02:00
parent 11a25afa0d
commit d1067a6feb
3 changed files with 240 additions and 54 deletions

View File

@ -1141,68 +1141,76 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
private UserVm rebootVirtualMachine(long vmId, boolean enterSetup, boolean forced) throws InsufficientCapacityException, ResourceUnavailableException {
UserVmVO vm = _vmDao.findById(vmId);
if (logger.isTraceEnabled()) {
logger.trace("reboot {} with enterSetup set to {}", vm, Boolean.toString(enterSetup));
}
if (vm == null || vm.getState() == State.Destroyed || vm.getState() == State.Expunging || vm.getRemoved() != null) {
logger.warn("Vm {} with id={} doesn't exist or is not in correct state", vm, vmId);
return null;
}
if (vm.getState() == State.Running && vm.getHostId() != null) {
collectVmDiskAndNetworkStatistics(vm, State.Running);
if (forced) {
Host vmOnHost = _hostDao.findById(vm.getHostId());
if (vmOnHost == null || vmOnHost.getResourceState() != ResourceState.Enabled || vmOnHost.getStatus() != Status.Up ) {
throw new CloudRuntimeException("Unable to force reboot the VM as the host: " + vm.getHostId() + " is not in the right state");
}
return forceRebootVirtualMachine(vm, vm.getHostId(), enterSetup);
}
DataCenterVO dc = _dcDao.findById(vm.getDataCenterId());
try {
if (dc.getNetworkType() == DataCenter.NetworkType.Advanced) {
//List all networks of vm
List<Long> vmNetworks = _vmNetworkMapDao.getNetworks(vmId);
List<DomainRouterVO> routers = new ArrayList<>();
//List the stopped routers
for (long vmNetworkId : vmNetworks) {
List<DomainRouterVO> router = _routerDao.listStopped(vmNetworkId);
routers.addAll(router);
}
//A vm may not have many nics attached and even fewer routers might be stopped (only in exceptional cases)
//Safe to start the stopped router serially, this is consistent with the way how multiple networks are added to vm during deploy
//and routers are started serially ,may revisit to make this process parallel
for (DomainRouterVO routerToStart : routers) {
logger.warn("Trying to start router {} as part of vm: {} reboot", routerToStart, vm);
_virtualNetAppliance.startRouter(routerToStart.getId(),true);
}
}
} catch (ConcurrentOperationException e) {
throw new CloudRuntimeException("Concurrent operations on starting router. " + e);
} catch (Exception ex) {
throw new CloudRuntimeException("Router start failed due to" + ex);
} finally {
if (logger.isInfoEnabled()) {
logger.info("Rebooting vm {}{}.", vm, enterSetup ? " entering hardware setup menu" : " as is");
}
Map<VirtualMachineProfile.Param,Object> params = null;
if (enterSetup) {
params = new HashMap<>();
params.put(VirtualMachineProfile.Param.BootIntoSetup, Boolean.TRUE);
if (logger.isTraceEnabled()) {
logger.trace(String.format("Adding %s to paramlist", VirtualMachineProfile.Param.BootIntoSetup));
}
}
_itMgr.reboot(vm.getUuid(), params);
}
return _vmDao.findById(vmId);
} else {
if (vm.getState() != State.Running || vm.getHostId() == null) {
logger.error("Vm {} is not in Running state, failed to reboot", vm);
return null;
}
collectVmDiskAndNetworkStatistics(vm, State.Running);
if (forced) {
return handleForcedReboot(vm, enterSetup);
}
try {
startRoutersIfNeeded(vm, vmId);
} catch (ConcurrentOperationException e) {
throw new CloudRuntimeException("Concurrent operations on starting router. " + e);
} catch (Exception ex) {
throw new CloudRuntimeException("Router start failed due to" + ex);
} finally {
if (logger.isInfoEnabled()) {
logger.info("Rebooting vm {}{}.", vm, enterSetup ? " entering hardware setup menu" : " as is");
}
Map<VirtualMachineProfile.Param, Object> params = buildRebootParamsIfNeeded(enterSetup);
_itMgr.reboot(vm.getUuid(), params);
}
return _vmDao.findById(vmId);
}
private UserVm handleForcedReboot(UserVmVO vm, boolean enterSetup) {
Host vmOnHost = _hostDao.findById(vm.getHostId());
if (vmOnHost == null || vmOnHost.getResourceState() != ResourceState.Enabled || vmOnHost.getStatus() != Status.Up) {
throw new CloudRuntimeException("Unable to force reboot the VM as the host: " + vm.getHostId() + " is not in the right state");
}
return forceRebootVirtualMachine(vm, vm.getHostId(), enterSetup);
}
private void startRoutersIfNeeded(UserVmVO vm, long vmId) throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException {
DataCenterVO dc = _dcDao.findById(vm.getDataCenterId());
if (dc.getNetworkType() != DataCenter.NetworkType.Advanced) {
return;
}
// List all networks of vm
List<Long> vmNetworks = _vmNetworkMapDao.getNetworks(vmId);
List<DomainRouterVO> routers = new ArrayList<>();
// List the stopped routers
for (long vmNetworkId : vmNetworks) {
List<DomainRouterVO> router = _routerDao.listStopped(vmNetworkId);
routers.addAll(router);
}
// Safe to start the stopped router serially, consistent with deploy/start behavior
for (DomainRouterVO routerToStart : routers) {
logger.warn("Trying to start router {} as part of vm: {} reboot", routerToStart, vm);
_virtualNetAppliance.startRouter(routerToStart.getId(), true);
}
}
private Map<VirtualMachineProfile.Param, Object> buildRebootParamsIfNeeded(boolean enterSetup) {
if (!enterSetup) {
return null;
}
Map<VirtualMachineProfile.Param, Object> params = new HashMap<>();
params.put(VirtualMachineProfile.Param.BootIntoSetup, Boolean.TRUE);
return params;
}
private UserVm forceRebootVirtualMachine(UserVmVO vm, long hostId, boolean enterSetup) {

View File

@ -91,6 +91,7 @@ import org.apache.cloudstack.backup.dao.BackupDao;
import org.apache.cloudstack.backup.dao.BackupScheduleDao;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
import org.apache.cloudstack.engine.cloud.entity.api.db.dao.VMNetworkMapDao;
import org.apache.cloudstack.resourcelimit.Reserver;
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.Scope;
@ -152,6 +153,7 @@ import com.cloud.network.dao.PhysicalNetworkDao;
import com.cloud.network.dao.PhysicalNetworkVO;
import com.cloud.network.element.UserDataServiceProvider;
import com.cloud.network.guru.NetworkGuru;
import com.cloud.network.router.VpcVirtualNetworkApplianceManager;
import com.cloud.network.rules.FirewallRuleVO;
import com.cloud.network.rules.PortForwardingRule;
import com.cloud.network.rules.dao.PortForwardingRulesDao;
@ -205,6 +207,7 @@ import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.exception.ExceptionProxyObject;
import com.cloud.utils.fsm.NoTransitionException;
import com.cloud.vm.dao.NicDao;
import com.cloud.vm.dao.DomainRouterDao;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDetailsDao;
import com.cloud.vm.snapshot.VMSnapshotVO;
@ -461,6 +464,15 @@ public class UserVmManagerImplTest {
@Mock
private BackupScheduleDao backupScheduleDao;
@Mock
private VMNetworkMapDao _vmNetworkMapDao;
@Mock
private DomainRouterDao _routerDao;
@Mock
private VpcVirtualNetworkApplianceManager _virtualNetAppliance;
MockedStatic<UnmanagedVMsManager> unmanagedVMsManagerMockedStatic;
@Mock
@ -4363,6 +4375,167 @@ public class UserVmManagerImplTest {
method.invoke(userVmManagerImpl, vmId);
}
@Test
public void testBuildRebootParamsIfNeededFalseReturnsNull() {
Object params = ReflectionTestUtils.invokeMethod(userVmManagerImpl, "buildRebootParamsIfNeeded", false);
Assert.assertNull(params);
}
@Test
public void testBuildRebootParamsIfNeededTrueAddsBootIntoSetup() {
@SuppressWarnings("unchecked")
Map<VirtualMachineProfile.Param, Object> params =
ReflectionTestUtils.invokeMethod(userVmManagerImpl, "buildRebootParamsIfNeeded", true);
assertNotNull(params);
assertEquals(1, params.size());
assertEquals(Boolean.TRUE, params.get(VirtualMachineProfile.Param.BootIntoSetup));
}
@Test
public void testStartRoutersIfNeededBasicZoneSkipsRouterOperations() throws Exception {
UserVmVO vm = mock(UserVmVO.class);
when(vm.getDataCenterId()).thenReturn(zoneId);
DataCenterVO dc = mock(DataCenterVO.class);
when(_dcDao.findById(zoneId)).thenReturn(dc);
when(dc.getNetworkType()).thenReturn(DataCenter.NetworkType.Basic);
ReflectionTestUtils.invokeMethod(userVmManagerImpl, "startRoutersIfNeeded", vm, vmId);
verify(_vmNetworkMapDao, never()).getNetworks(anyLong());
verify(_virtualNetAppliance, never()).startRouter(anyLong(), anyBoolean());
}
@Test
public void testStartRoutersIfNeededAdvancedZoneWithoutNetworksStartsNothing() throws Exception {
UserVmVO vm = mock(UserVmVO.class);
when(vm.getDataCenterId()).thenReturn(zoneId);
DataCenterVO dc = mock(DataCenterVO.class);
when(_dcDao.findById(zoneId)).thenReturn(dc);
when(dc.getNetworkType()).thenReturn(DataCenter.NetworkType.Advanced);
when(_vmNetworkMapDao.getNetworks(vmId)).thenReturn(Collections.emptyList());
ReflectionTestUtils.invokeMethod(userVmManagerImpl, "startRoutersIfNeeded", vm, vmId);
verify(_vmNetworkMapDao).getNetworks(vmId);
verify(_routerDao, never()).listStopped(anyLong());
verify(_virtualNetAppliance, never()).startRouter(anyLong(), anyBoolean());
}
@Test
public void testStartRoutersIfNeededAdvancedZoneStartsAllStoppedRouters() throws Exception {
UserVmVO vm = mock(UserVmVO.class);
when(vm.getDataCenterId()).thenReturn(zoneId);
DataCenterVO dc = mock(DataCenterVO.class);
when(_dcDao.findById(zoneId)).thenReturn(dc);
when(dc.getNetworkType()).thenReturn(DataCenter.NetworkType.Advanced);
when(_vmNetworkMapDao.getNetworks(vmId)).thenReturn(Arrays.asList(100L, 200L));
DomainRouterVO router1 = mock(DomainRouterVO.class);
DomainRouterVO router2 = mock(DomainRouterVO.class);
DomainRouterVO router3 = mock(DomainRouterVO.class);
when(router1.getId()).thenReturn(1000L);
when(router2.getId()).thenReturn(1001L);
when(router3.getId()).thenReturn(2000L);
when(_routerDao.listStopped(100L)).thenReturn(Arrays.asList(router1, router2));
when(_routerDao.listStopped(200L)).thenReturn(Collections.singletonList(router3));
ReflectionTestUtils.invokeMethod(userVmManagerImpl, "startRoutersIfNeeded", vm, vmId);
verify(_virtualNetAppliance).startRouter(1000L, true);
verify(_virtualNetAppliance).startRouter(1001L, true);
verify(_virtualNetAppliance).startRouter(2000L, true);
}
@Test
public void testStartRoutersIfNeededPropagatesRouterStartException() throws Exception {
UserVmVO vm = mock(UserVmVO.class);
when(vm.getDataCenterId()).thenReturn(zoneId);
DataCenterVO dc = mock(DataCenterVO.class);
when(_dcDao.findById(zoneId)).thenReturn(dc);
when(dc.getNetworkType()).thenReturn(DataCenter.NetworkType.Advanced);
when(_vmNetworkMapDao.getNetworks(vmId)).thenReturn(Collections.singletonList(100L));
DomainRouterVO router = mock(DomainRouterVO.class);
when(router.getId()).thenReturn(1000L);
when(_routerDao.listStopped(100L)).thenReturn(Collections.singletonList(router));
doThrow(new CloudRuntimeException("router start failed")).when(_virtualNetAppliance).startRouter(1000L, true);
assertThrows(CloudRuntimeException.class,
() -> ReflectionTestUtils.invokeMethod(userVmManagerImpl, "startRoutersIfNeeded", vm, vmId));
}
@Test
public void testHandleForcedRebootThrowsWhenHostNotFound() {
UserVmVO vm = mock(UserVmVO.class);
when(vm.getHostId()).thenReturn(42L);
when(hostDao.findById(42L)).thenReturn(null);
assertThrows(CloudRuntimeException.class,
() -> ReflectionTestUtils.invokeMethod(userVmManagerImpl, "handleForcedReboot", vm, false));
}
@Test
public void testHandleForcedRebootThrowsWhenHostNotUsable() {
UserVmVO vm = mock(UserVmVO.class);
when(vm.getHostId()).thenReturn(42L);
HostVO host = mock(HostVO.class);
when(hostDao.findById(42L)).thenReturn(host);
when(host.getResourceState()).thenReturn(com.cloud.resource.ResourceState.Enabled);
when(host.getStatus()).thenReturn(com.cloud.host.Status.Down);
assertThrows(CloudRuntimeException.class,
() -> ReflectionTestUtils.invokeMethod(userVmManagerImpl, "handleForcedReboot", vm, false));
}
@Test
public void testHandleForcedRebootReturnsNullWhenStopFails() {
UserVmVO vm = mock(UserVmVO.class);
when(vm.getId()).thenReturn(vmId);
when(vm.getHostId()).thenReturn(42L);
HostVO host = mock(HostVO.class);
when(hostDao.findById(42L)).thenReturn(host);
when(host.getResourceState()).thenReturn(com.cloud.resource.ResourceState.Enabled);
when(host.getStatus()).thenReturn(com.cloud.host.Status.Up);
doReturn(null).when(userVmManagerImpl).stopVirtualMachine(vmId, false);
Object result = ReflectionTestUtils.invokeMethod(userVmManagerImpl, "handleForcedReboot", vm, false);
Assert.assertNull(result);
}
@Test
public void testHandleForcedRebootSuccessWithEnterSetup() throws Exception {
UserVmVO vm = mock(UserVmVO.class);
when(vm.getId()).thenReturn(vmId);
when(vm.getHostId()).thenReturn(42L);
HostVO host = mock(HostVO.class);
when(hostDao.findById(42L)).thenReturn(host);
when(host.getResourceState()).thenReturn(com.cloud.resource.ResourceState.Enabled);
when(host.getStatus()).thenReturn(com.cloud.host.Status.Up);
UserVmVO stoppedVm = mock(UserVmVO.class);
doReturn(stoppedVm).when(userVmManagerImpl).stopVirtualMachine(vmId, false);
Pair<UserVmVO, Map<VirtualMachineProfile.Param, Object>> startedVm = new Pair<>(userVmVoMock, new HashMap<>());
doReturn(startedVm).when(userVmManagerImpl).startVirtualMachine(eq(vmId), isNull(), isNull(), eq(42L), anyMap(), isNull(), eq(false));
UserVm result = ReflectionTestUtils.invokeMethod(userVmManagerImpl, "handleForcedReboot", vm, true);
assertEquals(userVmVoMock, result);
verify(userVmManagerImpl).stopVirtualMachine(vmId, false);
}
private ServiceOfferingVO getMockedServiceOffering(boolean custom, boolean customSpeed) {
ServiceOfferingVO serviceOffering = mock(ServiceOfferingVO.class);
when(serviceOffering.getUuid()).thenReturn("offering-uuid");

View File

@ -438,4 +438,9 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
return null;
}
public static boolean isBlank(String str) {
return org.apache.commons.lang3.StringUtils.isBlank(str);
}
}